오류와 요청 제한
오류 응답 형식, 전체 HTTP 상태 코드 표, 요청 제한 동작, 그리고 Atlas Cloud에서 효과적인 재시도 전략.
오류 응답 형식
Atlas Cloud는 호출하는 API 영역에 따라 세 가지 오류 형식을 반환합니다. 파서를 작성하기 전에 어떤 형식인지 확인하세요.
LLM 프로토콜 엔드포인트와 미디어 생성 엔드포인트에서 사용됩니다:
{
"code": 401,
"msg": "unauthorized",
"request_id": "…",
"data": null
}모든 응답에는 X-Request-ID 헤더가 포함됩니다. 이 값을 로그로 남기세요 — 지원팀이 특정 호출을 추적하는 가장 빠른 방법입니다.
HTTP 상태 코드
| 상태 | 의미 | 대처 |
|---|---|---|
400 | 잘못된 요청: 파싱할 수 없는 본문, model 누락, 잘못된 콘텐츠 타입, 유효하지 않은 보존 헤더 또는 유효하지 않은 webhook_url | 요청을 수정하세요. msg 필드에 구체적인 문제가 표시됩니다 |
401 | 인증 실패 — 키가 없거나, 알 수 없거나, 만료됨 | 키를 확인하세요. URL 경로가 잘못되어도 401이 반환되므로 엔드포인트도 함께 확인하세요 |
402 | 잔액 부족 또는 Coding Plan 한도 소진 | 충전하세요 |
403 | 계정 또는 사용자에게 권한이 없음 — Coding Plan 키를 이를 허용하지 않는 모델에 사용한 경우를 포함합니다 | 키의 범위를 확인하거나 지원팀에 문의하세요 |
404 | 리소스를 찾을 수 없음. 모델의 경우 계정에서 사용할 수 없는 모델도 여기에 해당합니다 | 카탈로그와 대조해 모델 ID를 확인하세요 |
413 | 요청 본문이 50 MB를 초과함 | 인라인 Base64 대신 URL을 보내거나, 먼저 파일을 업로드하세요 |
429 | 요청 제한에 도달함 | 백오프 후 재시도하세요 — 아래를 참조하세요 |
451 | 해당 지역에서 차단됨 | 재시도 불가 |
500 | 내부 오류 | 한 번 재시도한 뒤에도 실패하면 요청 ID와 함께 알려 주세요 |
503 | 일시적으로 사용할 수 없음 | 백오프 후 재시도하세요 |
504 | 동기 요청이 최대 대기 시간을 초과함 | 비동기 흐름으로 전환해 폴링하세요 |
401이 언제나 키가 잘못되었다는 뜻은 아닙니다. 게이트웨이는 라우팅보다 먼저 인증을 수행하므로, 경로에 오타가 있어도 404가 아닌 401이 반환됩니다. 다른 곳에서 잘 동작하는 키라면 URL을 먼저 확인하세요.
작업 수준 오류 코드
비동기 작업이 실패하면 data.error_code에 HTTP 상태보다 구체적인 숫자 형태의 플랫폼 코드가 담깁니다. 예를 들어 1039는 입력이 콘텐츠 검수에서 거부되었음을 나타냅니다.
data.error에는 사람이 읽을 수 있는 설명이 들어 있습니다. 예측 ID와 함께 둘 다 로그로 남기세요.
요청 제한
요청 제한은 계정별, 모델별로 적용됩니다. 제한을 초과하면 429가 반환됩니다.
LLM과 미디어 엔드포인트는 X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After를 반환하지 않습니다. 남은 할당량을 응답 헤더에서 읽을 수 없으므로 클라이언트 쪽에서 백오프를 구현하세요.
예외는 /public/v1 결제 엔드포인트로, 이쪽의 429 응답에는 Retry-After가 포함됩니다.
프로덕션 워크로드에 더 높은 한도가 필요하다면 예상 요청량과 사용 모델 구성을 담아 문의해 주세요.
재시도 전략
429, 500, 503, 504와 네트워크 수준의 실패는 재시도하세요. 400, 401, 402, 403, 404, 451은 재시도하지 마세요 — 동일하게 실패합니다.
읽기 요청은 마음껏 재시도해도 됩니다. 다만 생성 요청의 재전송은 주의하세요. 타임아웃된 요청이라도 이미 접수되었을 수 있어, 무작정 재시도하면 두 번째 작업이 만들어지고 그만큼 과금될 수 있습니다. 비동기로 제출하고 폴링하는 방식을 택하면 응답을 놓치더라도 작업을 잃지 않습니다.
import time, random, requests
RETRYABLE = {429, 500, 503, 504}
def call_with_retry(url, payload, api_key, max_attempts=4):
for attempt in range(max_attempts):
response = requests.post(
url,
json=payload,
headers={"Authorization": f"Bearer {api_key}"},
timeout=60,
)
if response.status_code not in RETRYABLE:
return response
if attempt == max_attempts - 1:
break
# 지수 백오프 + 지터, 여러 클라이언트가 동시에 재시도하는 것을 방지
delay = min(2 ** attempt, 30) * (0.5 + random.random() / 2)
time.sleep(delay)
return response스트리밍 오류
스트리밍 요청이 스트림이 열리기 전에 실패하면 일반적인 HTTP 오류를 받게 됩니다. 스트림이 시작된 뒤에는 연결이 유지된 채 오류가 스트림 내부의 이벤트로 도착합니다 — 즉 스트리밍 호출의 200은 완전한 응답을 보장하지 않습니다. 스트림이 중간에 끊기는 경우를 반드시 처리하세요.
스트림에는 킵얼라이브 신호로 :으로 시작하는 SSE 주석 줄이 포함될 수도 있습니다. 이는 데이터가 아니므로 무시해야 합니다 — 대부분의 SSE 클라이언트가 알아서 처리하지만, 직접 만든 파서는 놓치는 경우가 많습니다.
도움 받기
문제를 알려 주실 때는 다음을 함께 보내 주세요:
- 실패한 응답의
X-Request-ID헤더 - 비동기 작업의 경우 예측 ID
- 정확한 모델 ID와 타임스탬프
지원을 통해 연락해 주세요.
관련 문서
Last updated on