오류 응답 형식
추론 API는 OpenAI와 같은 형식으로 오류를 돌려줍니다.
json
{
"error": {
"message": "Incorrect API key provided. ...",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key"
}
}코드에서는 error.code로 분기하세요. message는 사람이 읽는 설명이라 문구가 바뀔 수 있습니다. param이 있으면 그 필드가 원인입니다.
/v1/messages는 경우에 따라 Anthropic 형식(type: "error")으로 돌려줍니다.- 스트림이 시작된 뒤의 오류는 HTTP 상태가 아니라 스트림 안의 이벤트로 옵니다. 스트리밍을 보세요. 이벤트의
error.code는 아래 표와 같습니다(예:provider_unavailable,upstream_timeout). 이벤트에는Retry-After가 없으므로 몇 초 기다렸다 다시 보내세요.
상태 코드별 대처
| 상태 | type / code | 원인 | 재시도 |
|---|---|---|---|
| 400 | invalid_request_error / unsupported_parameter · unsupported_value · image_input_unsupported · context_length_exceeded | 파라미터 오류, 컨텍스트 초과, 모델이 지원하지 않는 옵션이나 이미지 입력 | 아니요. 요청을 고치세요 |
| 401 | authentication_error / missing_api_key · invalid_api_key | 키가 없거나, 틀렸거나, 만료됨 | 아니요. 키를 확인하세요 |
| 402 | insufficient_quota_error / insufficient_quota · spend_limit_exceeded | 크레딧 부족 또는 키의 지출 한도 도달 | 충전하거나 한도를 올린 뒤에 |
| 403 | permission_error / model_not_allowed · insufficient_scope | 키에 허용하지 않은 모델이나 스코프 | 아니요. 키 설정을 확인하세요 |
| 404 | invalid_request_error / model_not_found · job_not_found | 모델 ID가 틀렸거나, 계정 정책으로 쓸 수 없는 모델이거나, 작업이 만료됨 | 아니요 |
| 409 | idempotency_* | 같은 Idempotency-Key의 요청이 겹침. 아래 표 참고 | 경우에 따라 |
| 413 | invalid_request_error / request_too_large | 요청 본문이 상한을 넘음. 본문 크기 제한 | 줄여서 보내세요 |
| 429 | rate_limit_error / rate_limit_exceeded | 키의 분당 요청 수 초과 | 예. Retry-After초 뒤에 |
| 502 | api_error / backend_unavailable · upstream_error | 모델 공급사 오류 | 예. 간격을 늘려 가며 |
| 503 | api_error / model_warming | 모델을 시작하는 중 | 예. Retry-After초 뒤에 |
| 503 | api_error / provider_unavailable | 이 모델의 모든 공급 경로가 잠시 막힘. 요청은 실행되지 않음 | 예. Retry-After초(최대 30초) 뒤에 |
| 504 | api_error / upstream_timeout | 모델 공급사가 제때 응답하지 않음 | 예. 간격을 늘려 가며 |
공급사가 요청을 거절한 400은 공급사가 알려 준 필드와 코드를 param·code에 싣습니다(예: param: "reasoning_effort", code: "unsupported_value"). 필드는 호출한 API의 이름으로 바꿔 싣습니다 — Chat Completions 요청이면 공급사 와이어의 input이 아니라 messages입니다. 공급사의 원문 메시지는 싣지 않습니다.
ID가 맞는데 404 model_not_found가 나면 키의 허용 모델과 접근 정책을 확인하세요.
409: Idempotency-Key가 겹쳤을 때
| code | 뜻 | 대처 |
|---|---|---|
idempotency_in_progress | 같은 요청이 아직 처리 중입니다 | 새 키로 다시 보내지 말고 기다리세요 |
idempotency_key_reused | 같은 키로 본문이 다른 요청을 보냈습니다 | 요청마다 새 키를 만드세요 |
idempotency_response_not_replayable | 스트림이나 큰 응답이라 저장된 결과를 다시 돌려줄 수 없습니다 | 이미 실행됐습니다. 결과와 청구 내역을 확인하세요 |
503 model_warming
모델을 시작하는 중입니다. 요청은 실행되지 않았습니다. Retry-After초 후 같은 요청을 다시 보내세요. 모델에 따라 10–20분이 걸릴 수 있습니다.
레이트리밋
키마다 기본 분당 100회이고, 키 설정에서 바꿀 수 있습니다. 남은 양은 응답 헤더에 있습니다.
| 헤더 | 뜻 |
|---|---|
X-RateLimit-Limit | 이 키의 분당 한도 |
X-RateLimit-Remaining | 남은 횟수 |
X-RateLimit-Reset | 한도가 다시 차는 시각(Unix 밀리초) |
Retry-After | 429·503에서 다시 보내기까지 기다릴 시간(초) |
로그인, 회원가입 같은 인증 엔드포인트에는 더 낮은 한도가 따로 있습니다.
재시도 코드
OpenAI SDK는 429와 5xx를 기본 2번 자동으로 재시도합니다. SDK의 대기 시간은 짧으므로, 503 model_warming처럼 오래 기다려야 하는 경우는 직접 재시도하세요.
python
import os
import random
import time
from openai import APIStatusError, OpenAI
client = OpenAI(
base_url="https://api.everyais.com/v1",
api_key=os.environ["EVERYAIS_API_KEY"],
max_retries=0, # 아래에서 직접 다시 보냅니다
)
RETRYABLE = {429, 502, 503, 504}
def create_with_retry(attempts=5, **request):
for attempt in range(attempts):
try:
return client.chat.completions.create(**request)
except APIStatusError as error:
if error.status_code not in RETRYABLE or attempt == attempts - 1:
raise
wait = float(error.response.headers.get("retry-after") or 2 ** attempt)
time.sleep(wait + random.random())- 400·401·402·403·404는 다시 보내도 결과가 같습니다. 원인을 먼저 고치세요.
- 재시도할 때는
Idempotency-Key를 함께 보내 같은 요청이 두 번 실행되지 않게 하세요. 비디오 제출은 이 헤더를 지원하지 않습니다.
문의할 때
응답 헤더의 x-request-id, HTTP 상태, error.code를 알려 주세요.