오류와 요청 제한

오류 응답 형식, 전체 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

On this page