탐색으로 건너뛰기

오류

오류

BeatAPI는 모든 실패를 정해진 코드 중 하나로 알려 줍니다. code 또는 retryable로 분기하세요. message는 원인을 사람이 읽을 수 있게 설명한 영어 문장입니다. BeatAPI는 모델 뒤의 공급사를 밝히지 않으며 모델 측의 원본 응답 본문도 전달하지 않습니다. 유일한 예외는 텍스트 엔드포인트에서 모델이 반환하는 영어 입력 검증 문장으로, 입력을 고칠 수 있도록 그대로 전달합니다. 지원 요청을 위해 request_id를 보관하세요.

오류 객체

이미지·영상 작업, GET /v1/tasks/{task_id}, 기능, 워크플로, /v1/systemone(별칭 /v1/decisions 포함), /v1/moderations, /v1/social-data/call, /v1/web/* 등 BeatAPI의 모든 엔드포인트는 같은 형식으로 오류를 반환합니다.

{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded: at most 60 successful requests per 1 minute(s). Retry after 60 seconds.",
"retryable": true,
"request_id": "req_abc123",
"retry_after_seconds": 60
}
}
필드포함 조건의미
code항상아래 표의 코드입니다. 분기할 때는 이 값을 사용하세요.
message항상원인을 설명하는 영어 문장입니다. bad_request의 경우 해당 필드 이름이 들어갑니다. 사람과 로그를 위한 문장이므로 파싱하지 마세요.
retryable아래 표의 모든 코드같은 호출이 나중에 성공할 수 있으면 true입니다(표의 모든 429, 500, 503 코드). 요청, 키 또는 잔액을 바꾸기 전까지 다시 실패하면 false입니다. retryable이 false인 호출은 절대 반복하지 마세요. 표에 없는 코드에서만 이 필드가 빠질 수 있습니다.
request_id항상보관하세요. 지원팀이 이 값으로 호출을 찾습니다.
retry_after_seconds429 rate_limit_exceeded에서만기다려야 할 초 단위 시간입니다. 같은 값이 Retry-After 헤더로도 전송됩니다. 다른 코드에는 포함되지 않습니다. 503은 대기 시간을 알 수 없으므로 백오프를 적용해 재시도하세요.

POST /v1/chat/completions, POST /v1/responses, POST /v1/messages는 모델을 호출하기 전의 실패에는 이 형식을 사용하고, 호출 중의 실패에는 각 SDK 고유의 오류 형식을 유지합니다. 텍스트 엔드포인트를 참고하세요. Gemini 네이티브 엔드포인트(/v1beta/...)와 GET /v1/models는 이와 다른 더 단순한 형식을 사용하며, 같은 섹션에서 설명합니다.

POST /v1/moderations도 이 형식을 사용합니다. 이 엔드포인트에서는 오류 객체에 OpenAI의 type과 param도 포함되므로(param은 항상 null) OpenAI SDK가 평소와 같은 예외를 발생시킵니다. 콘텐츠 검수 API를 참고하세요.

실패가 나타나는 위치

작업은 두 시점에서 실패할 수 있으며, 각각 형태가 다릅니다.

  1. 생성할 때. 작업이 만들어지기 전에 요청이 거부됩니다. error 객체가 담긴 HTTP 오류를 받으며 data.id는 없습니다. 과금되지 않습니다.
  2. 접수된 후. POST가 data.id와 함께 201을 반환했고, 이후 작업이 status: "failed"로 끝납니다. GET /v1/tasks/{task_id}는 여전히 200을 반환하며, 실패 정보는 data.error_code, data.error_message, data.retryable에 있습니다. 작업을 위해 보류된 크레딧은 환불됩니다.
{
"error": {
"code": "content_policy_violation",
"message": "The request was blocked by content moderation. Please change the prompt or the input and try again.",
"retryable": false,
"request_id": "req_abc123"
}
}
{
"data": {
"id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
"status": "failed",
"error_code": "content_policy_violation",
"error_message": "The request was blocked by content moderation. Please change the prompt or the input and try again.",
"retryable": false
}
}

같은 실패는 두 위치 모두에서, 그리고 사용량 로그의 오류 줄(content_policy_violation: The request was blocked…)에서도 같은 코드를 갖습니다. 실패한 작업은 HTTP 오류가 아닙니다. GET /v1/tasks/{task_id}는 status: "failed", error_code, error_message, retryable과 함께 200을 반환하고, 작업을 위해 보류된 크레딧은 환불됩니다. 실패한 작업에서 usage.credits_reserved는 생성 시 보류된 금액이고, usage.credits_charged와 usage.credits_settled는 0이며, usage.credits_refunded는 환불된 금액입니다.

접수된 작업은 다음 여섯 가지 코드 중 하나로만 끝날 수 있습니다. 나머지 코드는 요청 시점의 거부입니다.

error_code의미retryable
content_policy_violation프롬프트, 입력 또는 결과가 콘텐츠 검수에서 거부되었습니다.false
bad_request모델이 파라미터를 거부했거나 가져올 수 없는 입력이 있습니다.false
processing_unavailable모델을 사용할 수 없거나 처리 용량이 가득 찼습니다.true
processing_timeout처리 제한 시간 안에 작업이 끝나지 않아 중단되었습니다.true
processing_failedBeatAPI 측의 다른 이유로 처리에 실패했습니다.true
result_transfer_failed결과는 생성되었지만 저장하지 못했습니다.true

시간 초과 정리 과정에서 실패 처리된 작업은 웹훅 이벤트를 보내지 않으므로 GET /v1/tasks/{task_id} 폴링을 계속하세요. 기준이 되는 정보는 폴링 결과입니다.

기능 실행

지연 실행된 기능이 실패하면 위의 공통 오류 형식(code, message, retryable, request_id)으로 응답하며, 상태 코드는 오류 코드에 따릅니다(processing_* 코드는 503). 이 실행은 과금되지 않습니다. 약 85초가 지나도 실행이 계속되면 대신 status: "running"과 함께 202를 반환합니다.

operation: "result"를 지정한 POST /v1/capabilities/run은 request_id로 저장된 결과를 읽습니다. 결과는 1시간 동안 보관됩니다. 저장된 결과가 없으면 404 result_expired(retryable: false)를 반환하므로 기능을 다시 실행하세요.

코드

코드HTTPretryable발생 조건조치
bad_request400falseJSON 형식이 잘못되었거나, 엔드포인트가 받지 않는 필드·값·조합(크기, 비율, 길이, 개수, 프롬프트 길이 등)이 있습니다. 메시지에 해당 필드가 표시됩니다. 다운로드할 수 없는 입력 URL이나 처리할 수 없는 파일도 여기에 해당합니다.지적된 필드를 수정하거나, 공개적으로 접근 가능한 HTTPS URL과 지원되는 형식을 사용하세요.
content_policy_violation400false프롬프트, 입력 또는 생성된 결과가 콘텐츠 검수에서 거부되었습니다.프롬프트나 입력을 바꾸세요. 같은 요청을 다시 보내지 마세요.
missing_api_key401falseAPI 키를 보내지 않았습니다.Authorization: Bearer <key>를 보내세요. 키는 sk- 접두사가 있어도 없어도 동작합니다.
invalid_api_key401false키가 잘못되었거나 만료, 비활성화, 소진되었습니다. 메시지에 원인이 표시됩니다. 삭제된 키는 즉시 실패합니다.대시보드에서 활성 키를 확인하거나 다른 키로 바꾸세요.
unauthorized401false401의 이전 이름으로, 2026-09-29부터 missing_api_key와 invalid_api_key로 대체되었습니다. 아직 나타날 수 있습니다.invalid_api_key와 같이 처리하세요.
insufficient_credits402false잔액 부족: 계정 잔액이 0이거나 이 요청의 가격보다 적습니다. 또는 키 자체의 지출 한도가 가격보다 낮은 경우로, 이때는 메시지에 그렇게 표시됩니다.충전하거나 키의 한도를 올린 뒤 요청을 다시 보내세요.
forbidden403false이 키나 계정으로는 이 호출을 할 수 없습니다. 예를 들어 무료 크레딧으로 쓸 수 없는 모델, 키의 IP 허용 목록 밖에서 보낸 요청, 키의 그룹에 속하지 않은 모델이 해당합니다.메시지를 확인하세요. 무료 크레딧 계정은 충전하면 모든 모델을 사용할 수 있습니다.
not_found404false텍스트·기능 엔드포인트에서 알 수 없거나 가격이 없는 모델, 알 수 없는 기능, 또는 이 계정에 존재하지 않는 작업입니다. 이미지·영상 작업 엔드포인트에서는 카탈로그에 없는 모델이 대신 400 bad_request로 반환됩니다(메시지에 카탈로그에 없다고 표시됨).ID와 키가 속한 계정을 확인하세요. 기능의 경우 suggestions를 사용하세요.
result_expired404falseoperation: "result"를 지정한 POST /v1/capabilities/run에서, 해당 request_id에 저장된 결과가 없을 때만 반환됩니다. 결과는 1시간 동안 보관됩니다.기능을 다시 실행하세요.
idempotency_conflict409falseIdempotency-Key를 다른 본문이나 경로에 재사용했거나, 이 키를 사용한 첫 요청이 아직 처리 중입니다.키는 완전히 같은 요청에만 재사용하세요.
rate_limit_exceeded429true키가 너무 많은 요청을 보냈습니다(무료 모델 한도 포함). 텍스트 엔드포인트에서는 모델 자체의 처리 용량이 가득 찼다는 뜻일 수도 있습니다(“This model is receiving too many requests”).Retry-After에 표시된 시간(또는 retry_after_seconds초)만큼 기다린 뒤 재시도하세요.
internal_error500true예상하지 못한 내부 오류입니다.한 번 재시도하고, 계속되면 request_id와 함께 지원팀에 문의하세요.
not_implemented501false공개된 엔드포인트이지만 이 게이트웨이에서는 아직 제공하지 않습니다.재시도하지 말고 다른 엔드포인트를 사용하세요.
processing_unavailable503trueBeatAPI 측에서 모델을 일시적으로 사용할 수 없거나 처리 용량이 가득 찼습니다. 파일 저장소를 일시적으로 사용할 수 없는 업로드도 해당합니다(“File storage is temporarily unavailable. Retry later; nothing was stored.”).나중에 백오프를 적용해 재시도하거나 다른 모델을 사용하세요.
processing_timeout503true처리가 제시간에 끝나지 않았습니다.백오프를 적용해 재시도하세요.
processing_failed503trueBeatAPI 측의 다른 이유로 처리에 실패했습니다.백오프를 적용해 재시도하세요.
result_transfer_failed503true결과는 생성되었지만 저장하지 못했습니다. 파일을 저장하지 못한 업로드도 해당합니다(“The file could not be stored on our side. Retry; nothing was stored.”).백오프를 적용해 재시도하세요.

이미지·영상 작업 엔드포인트에서 본문이 너무 크면 400 bad_request(“Request body is too large.”)입니다. 413 read_request_body_failed는 텍스트 엔드포인트에만 있으며 위 표에는 없습니다. 본문에 retryable 필드가 없습니다. 그대로 재시도해도 소용없으니 더 작은 본문을 보내세요. 아래를 참고하세요.

processing_unavailable과 rate_limit_exceeded는 서로 다릅니다. rate_limit_exceeded는 사용자 측의 요청 속도에 관한 것으로, 속도를 늦추라는 뜻입니다. processing_unavailable은 모델이 지금 작업을 받을 수 없다는 뜻이며, 요청 자체에는 문제가 없습니다.

BeatAPI는 502나 504를 반환하지 않습니다. 그래도 502 또는 504를 받았다면 BeatAPI에 연결할 수 없었던 네트워크 엣지에서 온 것이며, 본문은 JSON이 아닙니다. 503처럼 백오프를 적용해 재시도하세요. 본문이 error code: 1010인 403도 마찬가지입니다. 엣지가 클라이언트의 기본 User-Agent(예: Python의 urllib)를 거부한 것이므로 User-Agent를 명시적으로 보내세요.

Realtime 코드

이 코드는 Realtime 세션에서만 나타납니다. 웹훅 서명 검증은 받은 콜백을 직접 확인하는 절차이며, BeatAPI는 이에 대한 오류 코드를 반환하지 않습니다(웹훅 참고).

코드HTTPretryable발생 조건
realtime_disabled503false이 배포 환경에서는 Realtime Video가 활성화되어 있지 않습니다. 직접 처리할 방법은 없으니 지원팀에 문의하세요.
realtime_capacity_unavailable503trueRealtime 처리 용량을 일시적으로 사용할 수 없습니다. 잠시 후 백오프를 적용해 재시도하세요. 대기 시간은 안내되지 않습니다.
realtime_session_expired410false이 세션은 더 이상 사용할 수 없습니다. 새 세션을 만드세요.
origin_not_allowed403false이 세션에서 허용되지 않은 브라우저 오리진입니다.
invalid_client_secret401false세션의 클라이언트 시크릿이 유효하지 않거나 더 이상 사용할 수 없습니다.
transport_not_allowed400false요청한 전송 방식이 허용되지 않습니다.

텍스트 엔드포인트

POST /v1/chat/completions, POST /v1/responses, POST /v1/messages는 두 단계에서 실패할 수 있으며, 단계마다 본문 형식이 다릅니다.

1. 모델을 호출하기 전. 키가 없거나 유효하지 않은 경우, 무료 크레딧 제한, 키의 IP 허용 목록이나 그룹, 라우팅, 요청 속도 제한은 BeatAPI 오류 형식으로 응답합니다. code, message, retryable, request_id가 포함되며 429에는 retry_after_seconds와 Retry-After도 포함됩니다. 이 단계에서 알 수 없는 모델은 404 not_found입니다. 키의 IP 허용 목록 밖에서 보낸 요청이나 키의 그룹에 속하지 않은 모델은 403 forbidden입니다. /v1/chat/completions, /v1/responses, /v1/messages 모두 같습니다.

Gemini 네이티브 엔드포인트와 GET /v1/models. /v1beta/...와 GET /v1/models는 BeatAPI 오류 형식을 사용하지 않습니다. 오류는 {"error":{"message":"... (request id: ...)","type":"beatapi_error","code":...}} 형태이며 retryable이나 retry_after_seconds가 없습니다. 429에는 여전히 Retry-After 헤더가 포함됩니다.

2. 호출 중. OpenAI·Anthropic SDK가 파싱해 평소와 같은 예외를 발생시킬 수 있도록, 본문은 의도적으로 SDK 고유 형식을 유지합니다. retryable 필드는 없으므로 상태 코드와 오류 코드를 사용하세요. 이 단계에서는 모든 message 뒤에 요청 ID가 덧붙습니다. 여기서는 세 종류의 실패가 발생합니다.

  • 게이트웨이가 직접 거부한 경우에는 BeatAPI 코드(insufficient_credits, content_policy_violation, bad_request, not_found, internal_error)를 사용합니다.
  • 모델 측 실패는 temporary_error, upstream_timeout, model_unavailable, rate_limit_exceeded 중 하나의 코드와 함께 SDK 고유 형식으로 바꿔 반환하며, HTTP 상태는 유지합니다. 단, 502와 504는 503이 됩니다. 공급사와 관련된 BeatAPI 계정 측 문제는 503 model_unavailable로 보고합니다.
  • 모델이 반환한 영어 파라미터 오류(예: 컨텍스트 길이 초과)는 입력을 고칠 수 있도록 문장 그대로 전달합니다.

OpenAI 형식(/v1/chat/completions, /v1/responses):

{
"error": {
"message": "This API key's remaining quota is below the price of this request. Raise the key's quota in the console or use another key. (request id: req_abc123)",
"type": "beatapi_error",
"param": "",
"code": "insufficient_credits"
}
}

Anthropic 형식(/v1/messages):

{
"type": "error",
"error": {
"type": "insufficient_credits",
"message": "This API key's remaining quota is below the price of this request. Raise the key's quota in the console or use another key. (request id: req_abc123)"
}
}

게이트웨이가 직접 거부한 경우 OpenAI 형식에서는 type이 beatapi_error이고 BeatAPI 코드는 error.code에 들어갑니다. Anthropic 형식에서는 코드가 error.type에 들어갑니다.

HTTP코드조치
400bad_request 또는 content_policy_violation요청이나 입력을 수정하세요. 그대로 다시 보내지 마세요. 모델의 영어 파라미터 문장(예: 컨텍스트 초과)은 message로 전달됩니다.
402insufficient_credits충전하거나 키의 한도를 올리세요.
404not_found알 수 없는 모델입니다. GET /v1/models로 사용 가능한 모델 목록을 확인하세요.
413read_request_body_failed더 작은 본문을 보내세요. 이 코드에는 retryable 필드가 없습니다.
429rate_limit_exceeded요청 한도에 도달했거나 모델의 처리 용량이 가득 찼습니다. 백오프를 적용해 재시도하세요. 이 단계에서는 Retry-After가 보장되지 않습니다.
500internal_error(BeatAPI 측) 또는 temporary_error(모델 측)백오프를 적용해 한두 번 재시도하세요.
503model_unavailable, upstream_timeout 또는 temporary_error백오프를 적용해 재시도하거나 다른 모델을 사용하세요.

재시도 정책

  • 그대로 재시도하지 마세요(retryable: false): bad_request, content_policy_violation, missing_api_key, invalid_api_key, unauthorized, insufficient_credits, forbidden, not_found, result_expired, read_request_body_failed, idempotency_conflict, not_implemented, realtime_session_expired. 즉 모든 400, 401, 402, 403, 404, 409, 410, 413, 501이 해당합니다. read_request_body_failed에는 retryable 필드가 없고 코드 표에도 없지만 false로 취급하세요.
  • 기다린 뒤 재시도(retryable: true): rate_limit_exceeded. Retry-After / retry_after_seconds를 따르세요.
  • 백오프를 적용해 재시도(retryable: true): internal_error와 네 가지 503 코드(processing_unavailable, processing_timeout, processing_failed, result_transfer_failed). Realtime 503 코드는 다릅니다. realtime_capacity_unavailable은 재시도할 수 있고 realtime_disabled는 재시도할 수 없습니다. 지터를 넣은 지수 백오프와 상한을 사용하세요. 실패한 작업은 환불되었으므로, 새로운 시도는 성공할 때만 새로 과금됩니다. 작업 생성 시 Idempotency-Key를 보내면 제출을 재시도해도 두 번째 작업이 생기지 않습니다.

멱등성

Idempotency-Key는 작업 생성과 POST /v1/capabilities/run에서 선택 사항입니다.

  • 키는 24시간 동안 기억됩니다.
  • 255자를 넘는 키는 400 bad_request입니다.
  • 같은 키를 다른 본문이나 경로에 사용하면 409 idempotency_conflict입니다. 첫 요청이 아직 처리 중일 때 같은 키를 사용해도 마찬가지입니다.
  • 완전히 같은 요청을 반복하면 저장된 응답을 반환하고 Idempotent-Replayed: true 헤더를 추가합니다.
  • 2xx 응답만 저장됩니다. 400 또는 402 이후에는 같은 키로 재시도할 수 있습니다.

결과

결과 URL은 output.media[].url에 반환됩니다. 보관해야 하는 결과는 직접 다운로드해 저장하세요.

변경 내역

  • 2026-10-15 — 파일을 저장할 수 없는 업로드는 503(processing_unavailable 또는 result_transfer_failed)으로 응답하며 아무것도 저장되지 않습니다. 텍스트 호출 중 모델 측에서 실패하면 temporary_error, upstream_timeout, model_unavailable, rate_limit_exceeded와 함께 SDK 고유 형식으로 바꿔 반환하며, 이 단계의 모든 메시지 뒤에 요청 ID가 덧붙습니다.
  • 2026-10-15 — 지연 실행된 기능이 실패하면 이제 type: api_error가 담긴 본문이 아니라 공통 오류 형식(code, message, retryable, request_id)과 해당 코드의 상태로 응답합니다. retry_after_seconds와 Retry-After는 429 rate_limit_exceeded에서만 보내며 503에서는 보내지 않습니다. result_expired와 not_implemented를 표에 추가했습니다. 게이트웨이가 실제로 반환한 적이 없는 user_concurrency_exceeded와 invalid_signature는 삭제했습니다. 실패한 작업에서 usage.credits_charged는 0이고 usage.credits_refunded는 환불된 금액입니다. 텍스트 엔드포인트에서는 모델 호출 전의 실패에 BeatAPI 오류 형식을 사용하고, 호출 중의 실패에는 SDK 고유 본문을 유지합니다.
  • 2026-09-29 — 이제 401은 항상 missing_api_key(키를 보내지 않음) 또는 invalid_api_key(잘못되었거나 만료, 비활성화, 소진된 키, 메시지에 원인 표시)입니다. unauthorized는 두 경우의 이전 이름이며, 오래된 클라이언트에서 보이면 invalid_api_key처럼 처리하세요. 잔액 부족은 텍스트 엔드포인트를 포함한 모든 엔드포인트에서 항상 402 insufficient_credits입니다. retryable은 모든 오류에 포함되며, 모든 오류의 message는 원인을 설명하는 영어 문장입니다.
  • 2026-09-25 — BeatAPI는 더 이상 502나 504를 직접 반환하지 않습니다. 완료하지 못한 동기식 소셜 데이터·웹 호출과 백그라운드에서 실패한 리서치 실행(환불됨)을 포함해 모든 처리 실패(processing_unavailable, processing_timeout, processing_failed, result_transfer_failed)는 JSON 오류 본문이 담긴 503입니다. 그래도 502를 받았다면 BeatAPI에 연결할 수 없었던 엣지에서 온 것이며 본문은 JSON이 아닙니다. 백오프를 적용해 재시도하세요.
  • 2026-09-23 — 거부된 파라미터나 접근할 수 없는 입력 때문에 접수 후 실패한 작업은 이제 bad_request를 보고합니다(이전에는 processing_failed). 생성 시 모델 자체의 상태 코드는 더 이상 그대로 전달하지 않습니다. 콘텐츠 검수 거부는 항상 400 content_policy_violation이고, 모델을 사용할 수 없으면 503 processing_unavailable입니다. 생성 시 잔액이 부족하면 402 insufficient_credits입니다.