문제가 생겼을 때

오류 찾아보기

#오류 붙여 넣기

오류는 HTTP 상태 코드, error.type, error.code 순서로 읽으세요. 상태 코드는 항상 의미가 있고, type은 누가 호출을 거부했는지 알려 주며, code는 게이트웨이가 직접 발생시킨 오류에서만 안정적입니다.

#분기 처리 방법

  1. 1

    먼저 상태 코드로 분기

    402는 충전, 403은 키 권한 범위, 429는 대기, 5xx는 재시도를 뜻합니다. 이 계층은 거짓말하지 않고 바뀌지도 않습니다.

  2. 2

    error.type 확인

    xiaoxiang_error는 플랫폼의 오류입니다. 그 외의 값 — openai_error, claude_error, gemini_error — 은 제공업체 고유의 본문을 그대로 전달한 것입니다.

  3. 3

    그다음 error.code 읽기

    code로 분기하는 것은 xiaoxiang_error일 때만 하세요. 업스트림 code는 제공업체의 것이며 예고 없이 바뀔 수 있습니다.

모든 실패에 JSON 본문이 있는 것은 아님

속도 제한 거부와 너무 큰 본문은 상태 줄만 반환하고 중단됩니다. response.json()이 항상 성공한다고 가정한 파서는 오류 경로에서 오류를 처리하지 못하고 예외를 던집니다.
오류 구조

클라이언트에 도달하는 형식은 다섯 가지입니다. 다섯 가지를 모두 처리하세요 — 마지막 세 가지는 연동 시 흔히 놓치는 부분입니다.

게이트웨이 오류

게이트웨이가 직접 호출을 거부했습니다 — 인증, 한도, 라우팅, 요청 형식 문제입니다.

http
{
  "error": {
    "message": "insufficient account balance, please top up to continue (request id: 20260910...)",
    "type": "xiaoxiang_error",
    "code": "insufficient_user_quota"
  }
}

업스트림 오류(그대로 전달)

제공업체가 자체 오류로 응답했습니다. 본문이 그대로 전달되므로 type과 code는 제공업체의 값입니다.

http
{
  "error": {
    "message": "This model's maximum context length is 128000 tokens.",
    "type": "invalid_request_error",
    "code": "context_length_exceeded"
  }
}

가드 거부

멱등성 등 일부 사전 가드는 릴레이 오류 구조가 만들어지기 전에 응답합니다. 평면 구조이며 code는 대문자입니다.

http
{
  "code": "IDEMPOTENCY_IN_PROGRESS",
  "error": "a request with this Idempotency-Key is still processing"
}

비동기 작업 거부

모든 작업 엔드포인트는 — 동영상, 이미지 작업, 음악, 3D 모두 — 자체 평면 구조로 실패를 보고합니다. 여기에는 중첩된 error 객체가 없으므로 /v1/chat/completions 기준으로 작성한 파서는 null을 읽게 됩니다.

http
{
  "code": "task_not_exist",
  "message": "task does not exist",
  "data": null
}

상태 코드만, 본문 없음

속도 제한 거부와 너무 큰 요청 본문은 상태 코드만 반환하고 중단됩니다.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 20
Content-Length: 0
응답 헤더

실패할 때만이 아니라 모든 응답에서 요청 ID를 기록하세요. 지원팀이 호출을 추적하는 식별자이며, 5분 만에 답을 받느냐 하루 종일 추측하느냐를 가릅니다.

헤더전송 조건활용 방법
X-Oneapi-Request-Id성공이든 오류든 모든 응답.자체 trace ID와 함께 기록해 두세요. 지원팀은 이 값으로 문의 티켓을 처리하며, 게이트웨이 오류 메시지에도 같은 ID가 붙습니다.
Retry-After429일 때, 그리고 Idempotency-Key 요청이 아직 처리 중이라 409가 반환될 때.최소 이 초만큼 기다리세요. 게이트웨이가 보내는 유일한 백오프 힌트입니다.
X-Idempotent-Replayed같은 Idempotency-Key로 반복 요청해 저장된 응답이 재전송될 때.true이면 새 작업이 실행되지 않았고 다시 과금되지도 않았다는 뜻입니다 — 본문을 원래 결과로 처리하세요.
X-Idempotency-Sealed원래 응답을 안전하게 재전송할 수 없습니다(예: 스트림이거나 본문이 너무 큰 경우).해당 키로 재시도하지 마세요. 대신 작업 엔드포인트나 자체 기록으로 대조하세요.
log-the-request-id.ts
const response = await fetch(url, init);
const requestId = response.headers.get("X-Oneapi-Request-Id");

if (!response.ok) {
  // Bodies are absent on 429 and 413 — never assume JSON here.
  const detail = await response.text();
  logger.error({ status: response.status, requestId, detail });
  throw new GatewayError(response.status, requestId, detail);
}

#오류 코드 표

게이트웨이가 직접 발생시키는 오류로, type은 항상 "xiaoxiang_error"입니다. 두 행은 같은 429 상태 코드를 쓰지만 의미가 정반대입니다 — 백오프하기 전에 code를 읽으세요.

HTTP코드의미조치 방법재시도?
401없음Bearer 토큰이 없거나, 형식이 잘못되었거나, 삭제 또는 비활성화되었습니다. 이 계층은 code를 설정하지 않으므로 상태 코드로 판단하세요.Authorization 헤더를 확인하고, 콘솔 → API 키에서 키 상태를 확인하세요.아니요
401signature_required키에 요청 서명이 켜져 있는데 요청에 X-Timestamp, X-Nonce 또는 X-Signature가 없습니다.이 키로 보내는 모든 요청에 서명하거나(인증 및 키 → 요청 서명), 키에서 서명을 끄세요.아니요
401signature_expiredX-Timestamp가 10자리 Unix 초가 아니거나 서버 시간과 5분 넘게 차이 납니다. 응답에 X-Server-Timestamp가 포함됩니다.X-Server-Timestamp와의 차이만큼 클라이언트 시계를 보정하고 새 nonce로 다시 서명하세요.예
401signature_invalidX-Signature가 키의 서명 시크릿과 일치하지 않거나 X-Nonce 형식이 잘못되었습니다.타임스탬프, nonce, 메서드, 경로(쿼리 문자열 제외)를 줄바꿈으로 연결한 값을 콘솔 → API 키의 현재 시크릿으로 서명하세요.아니요
401signature_replayed이 X-Nonce는 최근 10분 내에 이 키로 이미 사용되었습니다.재시도를 포함해 모든 요청마다 새로운 무작위 nonce를 생성하세요.예
403access_denied호출한 IP가 키의 IP 허용 목록에 없습니다.콘솔 → API 키에서 송신(egress) 주소를 추가하거나, 고정 IP가 없는 키라면 허용 목록을 제거하세요.아니요
403없음계정이 정지되었거나, 키에 이 모델 또는 채널의 사용 권한이 없습니다.먼저 키의 모델 허용 목록을 확인하세요. 제한이 없다면 계정 자체가 차단된 것이니 문의 티켓을 여세요.아니요
400unsupported_endpoint모델은 있지만 이 경로를 지원하지 않습니다. 메시지에 지원하는 엔드포인트가 나열됩니다.나열된 엔드포인트로 호출을 옮기세요 — 이미지 작업 모델은 /v1/chat/completions에 응답하지 않습니다.아니요
400read_request_body_failed요청 본문을 읽을 수 없습니다 — 업로드가 잘렸거나, Content-Type이 잘못되었거나, 스트림이 일찍 끝났습니다.완전한 본문을 올바른 Content-Type과 함께 보내세요. 깨진 요청을 그대로 다시 보내면 똑같이 실패합니다.아니요
402insufficient_user_quota지갑 잔액이 이번 호출에 사전 차감할 금액보다 부족합니다.콘솔 → 지갑에서 충전한 뒤 다시 시도하세요.아니요
429insufficient_user_quota계정의 일일 지출 한도에 도달했습니다. 속도 제한과 상태 코드는 같지만 의미는 정반대이므로, 백오프로는 해소되지 않습니다.계정 설정에서 한도를 올리거나 해제하거나, 내일 다시 이어서 하세요. 429만 보지 말고 code로 분기하세요.아니요
429없음키별 RPM/RPD 속도 제한 또는 동시성 가드입니다. 본문은 비어 있으며, 대기 시간은 Retry-After에 담깁니다.Retry-After 초만큼 대기한 뒤, 지수 백오프와 지터를 적용해 재시도하세요.예
413read_request_body_failed요청 본문이 허용 크기를 넘었습니다. 전송 계층 제한에 걸리면 빈 본문과 함께 중단됩니다.페이로드를 줄이세요 — 파일은 /v1/media/upload-policy로 업로드하고 Base64 대신 URL을 보내세요.아니요
422invalid_request이 모델의 해당 미디어 의도를 지원하는 채널이 없습니다 — 예: 텍스트→동영상만 지원하는 경로에서 이미지→동영상 요청.모델 카드에서 지원하는 의도를 확인하고 모델이나 의도를 바꾸세요.아니요
503model_not_found알 수 없는 모델 이름이거나, 현재 이 모델을 제공하는 정상 채널이 없습니다. 상태 코드에 주의하세요. 알 수 없는 모델은 404가 아니라 503입니다./v1/models에서 이름을 확인한 뒤 재시도하세요 — 보통 다음 시도에서 페일오버가 정상 채널을 찾습니다.예
500sensitive_words_detected프롬프트가 게이트웨이를 떠나기 전에 콘텐츠 필터에 걸렸습니다.프롬프트를 바꾸세요. 같은 텍스트로 재시도하면 항상 실패합니다.아니요
500count_token_failed게이트웨이가 요금 계산용 토큰 수를 추정하지 못했습니다. 보통 메시지 배열 형식이 잘못된 경우입니다.messages 배열을 검증하세요. 형식에 문제가 없다면 재시도하고 요청 ID와 함께 문의 티켓을 여세요.예
500invalid_request요청을 이 엔드포인트가 받는 형식으로 파싱할 수 없습니다. 상태 코드에 주의하세요 — 게이트웨이가 읽을 수 없는 본문은 400이 아니라 500으로 보고됩니다.재시도하기 전에 엔드포인트 레퍼런스에 맞춰 JSON을 검증하세요.아니요
502do_request_failed제공업체에 연결할 수 없거나, 게이트웨이가 페일오버로 복구할 수 없는 실패를 반환했습니다.백오프를 적용해 재시도하세요 — 다음 시도는 대개 다른 채널로 갑니다.예
504do_request_failed제공업체가 게이트웨이 제한 시간 내에 응답하지 않았습니다.백오프를 적용해 재시도하세요. 프롬프트가 길거나 제공업체가 붐비면 타임아웃이 더 자주 발생합니다.예
499do_request_failed응답이 도착하기 전에 클라이언트가 연결을 닫았습니다 — 보통 클라이언트 자체 HTTP 타임아웃이 스트림 도중에 발동한 경우입니다.클라이언트 읽기 타임아웃을 늘리세요. 긴 생성 작업은 몇 분이 걸리며, 대부분의 HTTP 라이브러리 기본값으로는 부족합니다.아니요
멱등성 가드 오류

릴레이 앞단의 재전송 가드에서 발생하므로, OpenAI 오류 구조 대신 대문자 code를 쓰는 평면 {code, error} 형식을 사용합니다.

HTTP코드의미조치 방법재시도?
400IDEMPOTENCY_STREAM_UNSUPPORTED스트리밍 요청에 Idempotency-Key를 보냈습니다.스트리밍 호출에서는 이 헤더를 빼거나, 응답 재전송 보호가 필요하면 stream:false로 설정하세요.아니요
400IDEMPOTENCY_BODY_UNREADABLE멱등 원장에 기록할 본문 해시를 계산할 수 없습니다.일반 JSON 또는 multipart 본문을 보내세요 — 버퍼링할 수 없는 청크 본문은 거부됩니다.아니요
409IDEMPOTENCY_PAYLOAD_CONFLICT이 키는 이미 다른 본문, 경로 또는 쿼리에 사용되었습니다.새 키를 생성하세요. 키는 재시도 루프 전체가 아니라 정확히 하나의 요청을 식별합니다.아니요
409IDEMPOTENCY_IN_PROGRESS이 키를 사용한 첫 요청이 아직 실행 중입니다.Retry-After(2초)만큼 기다린 뒤 같은 키로 재시도하세요 — 원래 응답을 받게 됩니다.예
409IDEMPOTENCY_RESULT_UNREPLAYABLE원래 요청은 완료되었지만 응답이 봉인되어 재전송할 수 없습니다.무작정 다시 제출하지 마세요. 먼저 작업 엔드포인트나 자체 기록으로 대조하세요.아니요
503IDEMPOTENCY_UNAVAILABLE멱등 원장을 사용할 수 없어, 이중 과금 위험을 피하려고 가드가 요청을 차단(fail closed)합니다.백오프를 적용해 재시도하세요 — 요청은 실행되지 않았습니다.예

멱등 키 작동 방식 →

비동기 작업 오류

동영상, 이미지 작업, 음악, 3D 엔드포인트는 제출, 폴링, 취소 모두 자체 평면 형식 — {code, message, data} — 으로 응답합니다. 대비해야 할 특이 사항이 하나 있습니다. 알 수 없는 작업 ID를 폴링하면 400, 취소하면 404입니다.

HTTP코드의미조치 방법재시도?
400task_not_exist존재하지 않거나 다른 계정에 속한 작업 ID를 폴링하거나 리믹스했습니다. 상태 코드에 주의하세요 — 알 수 없는 작업을 폴링하면 400, 취소하면 404입니다.제출 시점에 task_id를 저장하고 정확히 그 값으로 폴링하세요.아니요
400invalid_request필수 필드가 없습니다 — 리믹스에는 prompt, 조회에는 task_id가 필요합니다.재시도하기 전에 본문이나 경로를 수정하세요.아니요
400task_channel_disable후속 작업(리믹스, 연장)은 원래 작업의 채널에 고정되는데, 그 채널이 현재 비활성화되어 있습니다.기존 작업에서 파생하지 말고 새 작업을 제출하세요.아니요
400invalid_source_task원본 작업의 종류가 이 요청과 맞지 않습니다 — 예: 3D 후속 작업에 동영상 ID를 전달한 경우.원본 ID가 같은 기능 계열에서 나온 것인지 확인하세요.아니요
404task_not_exist존재하지 않거나 내 것이 아닌 작업 ID를 취소하려 했습니다.취소할 대상이 없습니다 — 이미 사라진 것으로 처리하세요.아니요
409task_not_cancellable작업이 이미 최종 상태에 도달해 취소할 것이 없습니다.한 번 더 폴링해 이미 비용을 지불한 결과를 사용하세요.아니요
501task_cancel_not_supported이 작업을 처리하는 제공업체가 취소 API를 제공하지 않습니다. 대부분 제공하지 않습니다 — 취소는 예외일 뿐 일반적인 기능이 아닙니다.작업이 끝나도록 두세요. UI에서 취소는 보장이 아닌 최선의 시도로 설계하세요.아니요
502cancel_task_failed취소하는 동안 제공업체에 연결할 수 없었습니다. 작업은 변경되지 않았습니다.한 번 재시도하고, 그래도 안 되면 작업이 끝나도록 두세요.예

비동기 작업 수명 주기 →

아직 해결되지 않았나요?

요청 ID나 오류 메시지를 보내 주시면 확인해 드리겠습니다.