Errors & FAQ
에러 처리 방법과 자주 묻는 질문입니다.
HTTP 상태 코드
| 코드 | 설명 | 해결 방법 |
|---|---|---|
| 400 | 잘못된 요청 | 요청 형식 확인. Database API "Access denied"는 API 키 팀과 DB 소유 팀 불일치 |
| 401 | 인증 실패 | API 키 확인 |
| 402 | 크레딧 부족 | 크레딧 충전 |
| 403 | 접근 거부 | API 키 활성화 상태 확인 |
| 422 | 입력 검증 실패 | 파라미터 타입/값 확인 (예: output_format은 jpeg/png/webp만 허용) |
| 429 | 요청 한도 초과 | Retry-After 헤더 확인. 어떤 한도인지는 error.code로 구분 |
| 500 | 서버 오류 | 잠시 후 재시도 |
403 storage_quota_exceeded
팀이 스토리지 쿼터를 초과한 상태에서 POST /files/upload-url을 호출하면 이 코드와 함께 403이 반환됩니다. 파일당 50MB 제한과는 별개이며, 파일 총량이 한도를 넘으면 새 업로드가 거부됩니다. AI 예측 결과물은 이 쿼터로 차단되지 않습니다. 응답 형태: { "detail": { "code": "storage_quota_exceeded", "message": "..." } }. message는 바이트/파일 개수 한도 중 어느 쪽을 넘었는지에 따라 문구가 달라지는 설명 문자열입니다(변동될 수 있음) — 분기 처리는 항상 code 값으로 하세요. 해결: 오래된 파일 삭제(사용량은 GET /files/storage로 확인) 또는 상위 플랜 업그레이드. 리셀러 워크스페이스에서 end-customer별 한도(default_customer_storage_* 또는 지갑 storage_quota)를 걸어 두면 그 고객만 초과했을 때는 팀 쿼터가 남아 있어도 customer_storage_quota_exceeded로 거부됩니다 — 이 경우 고객 쪽 문구에는 팀 수치가 노출되지 않습니다.
코드는 표면마다 다릅니다
Core.Today는 두 개의 독립된 표면을 제공하고, 둘은 서로 다른 코드 집합을 씁니다. 아래 표의 “표면” 열이 어느 쪽이 그 코드를 내는지 알려줍니다.
- • AI API —
/v1/predictions,/v1/files,/v1/databases등. - • LLM 게이트웨이 — OpenAI·Anthropic·Gemini 호환 LLM 경로.
가장 흔한 함정: missing_api_key, invalid_api_key, api_key_disabled는 LLM 게이트웨이에만 존재합니다. AI API는 같은 상황에서 상태별 기본값인 unauthorized(401) / forbidden(403)을 반환합니다. POST /predictions 클라이언트가 invalid_api_key로 분기하면 그 가지는 영원히 실행되지 않습니다.
에러 응답 형태
에러 응답은 아래 봉투를 따릅니다. detail은 문자열일 수도, { code, message, … } 객체일 수도 있습니다 (422는 검증 항목 배열). 레이트리밋·용량 거절·쿼터 초과처럼 트래픽이 많은 경로는 대부분 객체 형태라 String(detail)을 하면 [object Object]가 찍힙니다. 표시는 error.message를, 분기는 error.code를 쓰세요 — message 문구는 예고 없이 다듬어집니다.
{
"detail": {
"code": "customer_wallet_insufficient",
"message": "End-customer 'acme-01' budget exhausted. Required: 120. Top up ..."
},
"error": {
"type": "api_error",
"code": "customer_wallet_insufficient",
"message": "End-customer 'acme-01' budget exhausted. ...",
"request_id": "3f2a9c1e-...",
"wallet_remaining": 30.0,
"topup_required": 90.0
},
"request_id": "3f2a9c1e-..."
}- •
request_id는 모든 응답의X-Request-Id헤더에도 실립니다. 문의 시 이 값을 함께 보내주시면 해당 요청의 서버 로그를 바로 찾을 수 있습니다. - • 코드별로
error에 추가 필드가 붙습니다 (예: 402의topup_required, 동시성 429의group/limit, 사용량 429의reset_at,model_retired의replacement). - • 재시도 가능한 응답에는
Retry-After헤더가 붙습니다. 공식 SDK는 이 값을 자동으로 존중합니다.
예외: 본문 크기 초과(413)는 이 봉투를 따르지 않습니다
AI API의 본문 상한(10MB)은 예외 핸들러보다 앞단의 미들웨어에서 검사되므로, 초과 시 응답은 { "detail": "Request body too large. Maximum size: 10MB" } 뿐입니다 — error 객체도, code도, request_id도 없습니다. 이 한 가지 응답만은 상태 코드 413으로 판별하세요. LLM 게이트웨이는 별개로 50 MiB 한도를 가지며, 그쪽은 정상적으로 request_too_large 코드를 냅니다.
에러 코드 레퍼런스 (동기 응답)
요청이 즉시 거절될 때 error.code로 전달되는 값입니다. “표면” 열이 어느 제품이 그 코드를 내는지, “원인 주체” 열이 누가 고쳐야 하는 문제인지 알려줍니다 — Core.Today로 표시된 항목은 요청 측 잘못이 아니며 키·잔액을 건드릴 필요가 없습니다.
| code | 표면 | 상태 | 원인 주체 | 재시도 | 의미 | 해결 방법 |
|---|---|---|---|---|---|---|
unauthorized | AI API | 401 | 요청 측 | 아니오 | AI API의 인증 실패 기본 코드 — 키 누락과 잘못된 키가 모두 이 값입니다. | AI API는 키 누락·무효를 코드로 구분하지 않습니다. 세부 사유는 message를 읽으세요. |
forbidden | AI API | 403 | 요청 측 | 아니오 | AI API의 권한 거부 기본 코드 — 비활성 키, 소유자·관리자 전용 작업 등. | 더 구체적인 코드가 없는 403입니다. message로 사유를 확인하세요. |
missing_api_key | LLM 게이트웨이 | 401 | 요청 측 | 아니오 | Authorization 또는 x-api-key 헤더가 없습니다. | 헤더에 API 키를 넣어 다시 호출하세요. AI API 쪽 같은 상황은 unauthorized입니다. |
invalid_api_key | LLM 게이트웨이 | 401 | 요청 측 | 아니오 | 존재하지 않거나 폐기된 키입니다. | 콘솔에서 키를 확인하세요. 이 코드는 '키가 실제로 없다'는 확정 응답입니다. |
api_key_disabled | LLM 게이트웨이 | 403 | 요청 측 | 아니오 | 키가 비활성화됐습니다. | 콘솔에서 키를 활성화하거나 새 키를 발급받으세요. |
api_key_expired | LLM 게이트웨이 | 403 | 요청 측 | 아니오 | 키의 만료 시각이 지났습니다. | 새 키를 발급받으세요. 만료는 되돌릴 수 없습니다. |
ip_not_allowed | LLM 게이트웨이 | 403 | 요청 측 | 아니오 | 호출 IP가 이 키의 허용 IP 목록에 없습니다. | 콘솔에서 키의 허용 IP를 수정하거나, 목록에 있는 곳에서 호출하세요. |
auth_service_unavailable | LLM 게이트웨이 | 503 | Core.Today | Retry-After 후 | 인증 서비스에 일시적으로 접근할 수 없어 키를 검증하지 못했습니다. | 키를 재발급하지 마세요 — 키에는 문제가 없습니다. Retry-After(10초) 후 재시도하면 됩니다. |
insufficient_scope | AI API | 403 | 요청 측 | 아니오 | 키에 이 엔드포인트 권한이 없습니다. | 필요한 scope를 가진 키로 호출하세요. |
ambiguous_auth | AI API | 400 | 요청 측 | 아니오 | 서로 다른 자격증명을 동시에 보냈습니다 (Clerk 세션 + X-API-Key, 또는 X-API-Key + X-Phantom-Token). | 어느 쪽으로 인증할지 모호하므로 거부됩니다. 하나만 보내세요. |
phantom_token_missing | AI API | 401 | 요청 측 | 아니오 | 리셀러 브라우저 경로: X-Phantom-Token 헤더가 없습니다. | 서버에서 phantom token을 발급해 클라이언트에 전달하세요. |
phantom_token_invalid | AI API | 401 | 요청 측 | 아니오 | phantom token의 서명이 틀렸거나, 만료됐거나, 폐기됐습니다. | 새 토큰을 발급하세요. 원본 API 키를 교체할 필요는 없습니다. |
reseller_mode_required | AI API | 403 | 요청 측 | 아니오 | 리셀러 전용 기능인데 워크스페이스가 리셀러 모드가 아닙니다. | 콘솔에서 리셀러 모드를 신청하세요. 승인 후 즉시 반영됩니다. |
customer_id_required | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | 리셀러 워크스페이스의 과금 요청인데 X-Customer-Id가 없습니다. | end-customer를 식별할 수 없으면 fail-closed로 거부합니다. 헤더를 붙이세요. |
ambiguous_customer_id | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | X-Customer-Id 헤더가 두 번 이상 들어왔습니다. | 프록시나 SDK가 헤더를 중복 추가하고 있는지 확인하세요. 정확히 하나만 허용됩니다. |
invalid_customer_id | 둘 다 | 400 | 요청 측 | 아니오 | X-Customer-Id 형식 위반 — 허용 문자는 A-Z a-z 0-9 _ . - 이고 최대 128자입니다. | 고객 식별자를 정규화한 뒤 다시 호출하세요. |
customer_mismatch | AI API | 403 | 요청 측 | 아니오 | 요청한 리소스가 X-Customer-Id로 지정한 end-customer의 것이 아닙니다. | 다른 고객의 데이터에 접근할 수 없습니다. 올바른 customer_id로 호출하세요. |
bad_request | AI API | 400 | 요청 측 | 아니오 | AI API의 400 기본 코드 — 더 구체적인 코드가 없는 요청 거부입니다. | message에 사유가 들어 있습니다. |
validation_error | AI API | 422 | 요청 측 | 아니오 | 요청 본문이 스키마와 맞지 않습니다. | 응답의 error.errors 배열에 어떤 필드가 왜 거부됐는지 들어 있습니다. |
not_found | 둘 다 | 404 | 요청 측 | 아니오 | AI API: 존재하지 않는 모델·리소스입니다. 게이트웨이: 존재하지 않는 엔드포인트(base_url 오타 등)입니다. | 모델이라면 GET /providers/models/catalog로 사용 가능한 목록을 확인하세요. |
method_not_allowed | LLM 게이트웨이 | 405 | 요청 측 | 아니오 | 메서드가 맞지 않습니다 — /models와 /pricing은 GET 전용입니다. | GET으로 호출하세요. |
unknown_api_type | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | URI가 어떤 프로바이더 경로에도 해당하지 않습니다. | 경로 접두사를 확인하세요 (/openai/v1/..., /anthropic/v1/..., /gemini/v1beta/...). |
unsupported_model | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | LLM 게이트웨이가 지원하지 않는 모델명입니다. | GET /llm/v1/pricing으로 지원 모델 목록을 확인하세요. |
model_retired | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | 은퇴한 모델입니다. | 응답의 replacement 필드가 대체 모델을 알려줍니다. |
model_not_determinable | LLM 게이트웨이 | 400 | 요청 측 | 아니오 | 과금 대상 요청인데 URL과 본문 어디에서도 모델을 특정할 수 없습니다 (주로 Gemini 경로). | 모델을 특정할 수 없으면 가격도 계산할 수 없어 거부합니다. 모델명을 명시하세요. |
request_too_large | LLM 게이트웨이 | 413 | 요청 측 | 아니오 | 요청 본문이 게이트웨이 한도 50 MiB를 초과했습니다. | 이미지는 파일 업로드 URL을 거쳐 참조로 전달하세요. AI API의 413은 별도 한도(10MB)이며 아래 경고 참조. |
(코드 없음) | AI API | 413 | 요청 측 | 아니오 | AI API 본문이 10MB를 초과했습니다. 미들웨어가 예외 핸들러를 우회하므로 error·code·request_id가 모두 없습니다. | 이 응답만은 code로 분기할 수 없습니다 — 상태 413으로 판별하세요. 큰 입력은 업로드 URL로 보내세요. |
request_body_read_failed | LLM 게이트웨이 | 400 | 요청 측 | 예 | 요청 본문을 끝까지 읽지 못했습니다 (전송 중 연결 끊김 등). 크기 초과와는 다릅니다. | 그대로 재시도하세요. 반복되면 클라이언트 쪽 네트워크·타임아웃을 확인하세요. |
input_nesting_too_deep | AI API | 400 | 요청 측 | 아니오 | input 객체의 중첩 깊이가 한도를 넘었습니다. | 입력을 평탄화하세요. 깊은 중첩은 파싱 비용 방어를 위해 거부됩니다. |
too_many_file_references | AI API | 400 | 요청 측 | 아니오 | 한 요청에 담긴 파일 참조 수가 한도를 넘었습니다. | 참조를 나눠 여러 요청으로 보내세요. |
insufficient_credits | 둘 다 | 402 | 요청 측 | 아니오 | 팀 크레딧이 부족합니다. | 크레딧을 충전하세요. error.required / error.available에 필요·보유량이 있습니다. |
payment_required | LLM 게이트웨이 | 402 | 요청 측 | 아니오 | 잔액 관련 사유로 거절됐지만 세부 코드가 전달되지 않았을 때 쓰이는 402 폴백입니다. | 실질적으로 insufficient_credits와 동일하게 다루세요 — 잔액을 확인하고 충전하세요. |
customer_not_found | 둘 다 | 402 · 404 | 요청 측 | 아니오 | 리셀러: X-Customer-Id가 이 워크스페이스에 등록되어 있지 않습니다. 과금 경로에서는 402, phantom-token 인증 경로에서는 404입니다. | 404를 '리소스 없음'으로 처리하지 마세요 — 상태가 아니라 code로 분기해야 합니다. POST /reseller/customers로 먼저 고객을 생성하세요. |
team_blocked | AI API | 403 | 요청 측 | 아니오 | 관리자가 이 워크스페이스의 이용을 차단했습니다(이상 사용·약관 위반 등). API 키·LLM·MCP 호출과 크레딧 차감 경로가 모두 거부되며, 콘솔 열람은 가능합니다. | 콘솔 상단 배너의 사유를 확인하고 support@core.today 로 문의하세요. 재시도해도 해제 전까지는 같은 응답입니다. |
customer_suspended | 둘 다 | 402 · 403 | 요청 측 | 아니오 | 리셀러: 해당 end-customer가 정지 상태입니다. 과금 경로에서는 402, phantom-token 인증 경로에서는 403입니다. | POST /reseller/customers/{id}/reactivate로 활성화하세요. |
customer_wallet_insufficient | 둘 다 | 402 | 요청 측 | 아니오 | 리셀러: end-customer 예산이 소진됐습니다. | error.topup_required만큼 충전하세요 (wallet_cap / wallet_spent / wallet_remaining 동봉). |
reseller_account_insufficient | 둘 다 | 402 | 요청 측 | 아니오 | 리셀러: end-customer 예산은 남았지만 리셀러 본계정(워크스페이스) 크레딧이 부족합니다. | 고객 지갑이 아니라 워크스페이스를 충전해야 합니다 — customer_wallet_insufficient와 혼동하지 마세요. |
addon_past_due | AI API | 409 | 요청 측 | 아니오 | 스토리지 애드온 갱신 결제가 연체 상태입니다. | 연체를 해소한 뒤 다시 시도하세요. 재시도만으로는 풀리지 않습니다. |
conflict | AI API | 409 | 요청 측 | 아니오 | AI API의 409 기본 코드 — 현재 리소스 상태와 충돌하는 요청입니다. | 리소스 상태를 다시 읽고 요청을 조정하세요. |
document_not_found | AI API | 404 | 요청 측 | 아니오 | Data API: PUT/PATCH/GET/DELETE 대상 문서가 없습니다. (2026-09-12 이전에는 400에 내부 오류 문자열이 실려 나갔습니다.) | 없으면 생성하고 싶다면 PUT/PATCH에 ?upsert=true를 붙이세요 — 응답 result가 created|updated를 알려줍니다. |
document_already_exists | AI API | 409 | 요청 측 | 아니오 | Data API: POST /documents는 생성 전용인데 그 id의 문서가 이미 있습니다. 덮어쓰지 않습니다. | 기존 문서를 바꾸려면 PUT(전체 교체) 또는 PATCH(부분 병합)를 쓰세요. 생성/수정 구분 없이 쓰려면 ?upsert=true. |
document_conflict | AI API | 409 | 요청 측 | 예 | Data API: 같은 문서가 동시에 수정되어 이번 쓰기가 밀렸습니다. 서버가 3회 자동 재시도한 뒤에도 충돌한 경우입니다. | 요청을 그대로 다시 보내세요(PATCH 병합은 멱등입니다). |
db_rate_limited | AI API | 429 | 요청 측 | Retry-After 후 | Data API: 워크스페이스의 분당 요청 예산(조회/검색/쓰기 클래스별, 플랜에 따라 다름)을 넘었습니다. 거부된 요청은 과금되지 않습니다. | Retry-After 뒤 재시도하세요. error.op_class와 error.limit가 어떤 예산인지 알려줍니다. 지속적으로 부족하면 플랜 상향. |
invalid_where | AI API | 400 | 요청 측 | 아니오 | Data API: where 필터가 JSON 객체가 아니거나 알 수 없는 연산자·필드명·잘못된 값 형태를 담고 있습니다. 과금 전에 거부됩니다. | 메시지가 가리키는 연산자/필드를 고치세요. 지원 연산자: $eq $ne $in $nin $gt $gte $lt $lte $exists $prefix $contains $match $and $or $not. |
embedding_failed | AI API | 502 | 모델 제공사 | 예 | Data API: embed 설정된 knn_vector 필드의 자동 임베딩 호출(LLM 게이트웨이)이 실패해 쓰기를 중단했습니다. 아무것도 저장되지 않았습니다. 워크스페이스에 활성 API 키가 없거나(콘솔 쓰기), 게이트웨이가 크레딧 부족·오류를 반환한 경우입니다. | 요청을 그대로 재시도하세요. 반복되면 크레딧 잔액과 API 키 상태를 확인하거나, 벡터를 직접 계산해 필드에 넣어 보내면 임베딩 호출을 건너뜁니다. |
precondition_failed | AI API | 412 | 요청 측 | 아니오 | Data API: If-Match로 보낸 _meta.version 이후에 문서가 변경되었습니다. 아무것도 쓰지 않았습니다. | 문서를 다시 읽고(GET → 새 _meta.version) 변경을 다시 적용한 뒤 새 If-Match로 재시도하세요. |
invalid_if_match | AI API | 400 | 요청 측 | 아니오 | Data API: If-Match 값이 <seq_no>.<primary_term> 형식이 아닙니다. 과금 전에 거부됩니다. | 응답의 _meta.version(또는 GET의 ETag)을 그대로 되돌려 보내세요. |
database_reindexing | AI API | 409 | 요청 측 | Retry-After 후 | Data API: 데이터베이스가 재색인(스키마 변경) 중이라 쓰기를 받을 수 없습니다. 조회·검색은 됩니다. | GET /databases/{uid}/reindex로 진행 상황을 확인하고 done이 되면 재시도하세요(Retry-After 참고). |
job_already_running | AI API | 409 | 요청 측 | Retry-After 후 | Data API: 이 데이터베이스에 같은 종류의 작업(export/import)이 이미 진행 중입니다. | GET /databases/{uid}/export 또는 /import로 상태를 확인하고 끝난 뒤 다시 시작하세요. |
import_fetch_failed | AI API | 400 | 요청 측 | 아니오 | Data API: 가져오기 URL을 받을 수 없습니다 — 사설망 주소, 50 MB 초과, 타임아웃 또는 비-2xx 응답. | 공개 http(s) URL(또는 Core.Today 파일 URL)인지, 50 MB 이하인지 확인하세요. |
database_unavailable | AI API | 503 | Core.Today | Retry-After 후 | Data API: 문서 저장소(OpenSearch/S3)에 일시적으로 쓰지 못했습니다. 차감된 크레딧은 환불됩니다. | Retry-After(2초) 뒤 재시도하세요. 지속되면 status.core.today를 확인하세요. |
credit_service_unavailable | LLM 게이트웨이 | 503 | Core.Today | Retry-After 후 | 크레딧 서비스 장애로 요청을 승인하지 못했습니다. | 잔액에는 문제가 없고 차감도 되지 않았습니다. Retry-After 후 재시도하면 됩니다. |
reserve_in_flight | LLM 게이트웨이 | 409 | Core.Today | Retry-After 후 | 같은 request_id의 예약이 아직 처리 중입니다. | 1초 후 재시도하세요. 일시적 상태입니다. |
rate_limited | 둘 다 | 429 | 요청 측 | Retry-After 후 | 게이트웨이: 키의 분당 LLM 토큰 한도를 넘었습니다. AI API: 더 구체적인 코드가 없는 429의 기본값입니다. | Retry-After만큼 기다린 뒤 재시도하세요. X-RateLimit-Reset이 한도 초기화 시각을 알려줍니다. |
api_key_rate_limited | AI API | 429 | 요청 측 | Retry-After 후 | API 키의 분/시/일 요청 한도를 넘었습니다. | Retry-After만큼 기다린 뒤 재시도하세요. 차감된 크레딧은 없습니다. |
customer_rate_limited | AI API | 429 | 요청 측 | Retry-After 후 | 리셀러: end-customer 개인 요청 한도를 넘었습니다. | Retry-After 후 재시도하거나 지갑의 rate_limit을 상향하세요. |
customer_concurrency_exceeded | 둘 다 | 429 | 요청 측 | Retry-After 후 | 리셀러: end-customer의 카테고리별 동시 실행 한도에 도달했습니다 (error.group / error.limit 참조). | 진행 중인 작업이 끝나면 재시도하세요. 차감된 크레딧은 없습니다. |
admission_queue_full | AI API | 429 | 모델 제공사 | Retry-After 후 | 이 모델의 프로바이더 동시성 풀(admission 큐)이 이미 가득 차 있어 요청이 즉시 거부되었습니다 — 대기조차 시작하지 않았습니다. 대기 후 실패하는 admission_timeout과 달리 요청 생성 시점에 바로 반환되는 동기 오류입니다. | 크레딧은 차감되지 않습니다. `retry_after` 후 재제출하세요. |
customer_token_rate_limited | LLM 게이트웨이 | 429 | 요청 측 | Retry-After 후 | 리셀러: end-customer의 분당 LLM 토큰 한도를 넘었습니다. | 다음 분까지 기다리거나 지갑의 llm_tokens_per_minute를 상향하세요. |
model_rate_limited | LLM 게이트웨이 | 429 | 요청 측 | Retry-After 후 | 해당 모델에 설정된 분당 요청 한도를 넘었습니다. | Retry-After 후 재시도하세요. 예약했던 토큰 예산은 되돌려집니다. |
usage_limit_exceeded | AI API | 429 | 요청 측 | 아니오 | 일/월 크레딧 사용 한도를 소진했습니다. 속도 제한이 아닙니다. | 재시도해도 소용없습니다 — error.reset_at까지 기다리거나 한도를 상향하세요. |
storage_quota_exceeded | AI API | 403 | 요청 측 | 아니오 | 팀 스토리지 쿼터를 초과했습니다. | 오래된 파일을 삭제하거나 플랜을 상향하세요. |
customer_scope_required | AI API | 400 | 요청 측 | 아니오 | 리셀러 워크스페이스에서 end-customer 스코프가 필요한 호출(고객 DB 문서 API, 파일 삭제)에 X-Customer-Id도 X-Customer-Scope: all도 없었습니다. 누락을 '전체 접근'으로 해석하지 않습니다 — 프록시가 헤더를 빠뜨렸을 때 고객 격리가 조용히 풀리는 것을 막기 위한 fail-closed입니다. | 회원을 대신한 호출이면 X-Customer-Id를, 리셀러 자신의 관리 작업이면 X-Customer-Scope: all을 명시하세요. |
customer_storage_quota_exceeded | AI API | 403 | 요청 측 | 아니오 | 리셀러: 이 end-customer(X-Customer-Id)에게 배정된 스토리지 한도(바이트 또는 파일 수)가 가득 찼습니다. 팀 전체 쿼터와는 별개이며 업로드 URL 발급 시점에만 검사됩니다. | 고객이 파일을 삭제하게 하거나, 리셀러가 PATCH /reseller/customers/{id}의 storage_quota로 한도를 올리세요 (즉시 반영). 기본 한도는 PATCH /reseller/settings의 default_customer_storage_*. |
capacity_exceeded | AI API | 503 | Core.Today | Retry-After 후 | 서버가 처리 중인 예측이 너무 많습니다. | 차감된 크레딧은 없습니다. Retry-After 후 재시도하세요. |
heavy_capacity_exceeded | AI API | 503 | Core.Today | Retry-After 후 | 비디오·음악 등 장시간 작업이 한도에 도달했습니다. | 차감된 크레딧은 없습니다. Retry-After 후 재시도하세요. |
job_store_unavailable | AI API | 503 | Core.Today | Retry-After 후 | 작업 생성 중 상태 저장소에 접근하지 못했습니다. 작업은 시작되지 않았고 크레딧은 환불됩니다. | 재제출해도 안전합니다 (시작된 작업이 없으므로 중복 실행 위험 없음). |
job_status_unavailable | AI API | 503 | Core.Today | Retry-After 후 | 이미 실행 중인 작업의 상태를 조회하지 못했습니다. 작업 자체는 영향받지 않습니다. | 재제출하지 마세요 — 작업은 계속 실행 중이며, 재제출하면 이중 과금됩니다. Retry-After 후 같은 job_id로 다시 조회하세요. |
job_not_found_or_expired | AI API | 404 | 요청 측 | 아니오 | job_id가 잘못됐거나, 작업 레코드 보관 기간(24시간)이 지났습니다. | 24시간이 지나도 완료된 작업은 폴백 조회로 200과 결과가 복원될 수 있습니다 (같은 사용자 자격증명으로 조회할 때). 404가 확정되면 결과물은 GET /files나 사용 내역에서 찾으세요. |
internal_error | 둘 다 | 500 | Core.Today | 예 | 예상치 못한 서버 오류입니다. | 재시도해도 안전합니다. 반복되면 응답의 request_id와 함께 문의해 주세요. |
service_unavailable | AI API | 503 | Core.Today | Retry-After 후 | AI API의 503 기본 코드 — 더 구체적인 코드가 없는 일시적 이용 불가입니다. | Retry-After 후 재시도하세요. |
upstream_error | AI API | 502 | Core.Today | 예 | AI API의 502 기본 코드 — 상위 의존 서비스가 응답하지 않았습니다. | 요청 측 문제가 아닙니다. 잠시 후 재시도하세요. |
proxy_error | LLM 게이트웨이 | 502 | Core.Today | 예 | 게이트웨이가 프로바이더에 도달하지 못했습니다. | 요청 내용과 무관합니다. 잠시 후 재시도하고, 지속되면 request_id와 함께 문의해 주세요. |
upstream_auth_failure | LLM 게이트웨이 | 503 | Core.Today | Retry-After 후 | 게이트웨이의 프로바이더 자격증명에 문제가 생겼습니다 (키 풀이 모두 소진). | 고객 키와 무관합니다. Retry-After 후 재시도하고, 지속되면 문의해 주세요. |
provider_not_configured | LLM 게이트웨이 | 503 | Core.Today | 아니오 | 요청한 프로바이더가 이 게이트웨이에 설정되어 있지 않습니다. 상태는 503이지만 일시적 장애가 아닙니다. | 재시도해도 해결되지 않습니다 — 503이라고 해서 백오프 재시도하지 마세요. 지원팀에 문의해 주세요. |
stream_interrupted | LLM 게이트웨이 | 200 · SSE | 모델 제공사 | 예 | 스트리밍 응답이 도중에 끊겼습니다. 헤더는 이미 200으로 나간 뒤라 상태 코드로는 알릴 수 없어, 본문 안에 event: error 프레임으로 주입됩니다. | content delta만 읽는 클라이언트는 이 프레임을 버리고 뒤따르는 [DONE]을 정상 종료로 착각합니다. 스트림 루프에서 반드시 error 필드를 확인하세요. 크레딧은 업스트림이 보고한 사용량 기준으로만 정산됩니다. |
에러 코드 레퍼런스 (예측 실패)
POST /predictions는 즉시 job_id를 반환하므로, 실제 실패 사유는 GET /predictions/{job_id} 응답의 error_code로 전달됩니다 (status는 failed). 이 표는 AI API 전용입니다.
실패한 예측의 크레딧은 자동 환불됩니다. 다만 credits_used가 0인지로 환불 여부를 판정하지는 마세요 — 오래된 레코드와 만료 후 폴백 조회는 이 값이 null(“알 수 없음”)입니다. 실제 청구 내역은 사용량·청구 API를 기준으로 확인하세요.
| code | 상태 | 원인 주체 | 재시도 | 의미 | 해결 방법 |
|---|---|---|---|---|---|
invalid_input | failed | 요청 측 | 아니오 | 프로바이더가 입력을 거부했습니다 (400/422). | 모델 상세 문서의 입력 스키마와 대조하세요. |
payload_too_large | failed | 요청 측 | 아니오 | 입력 파일·본문이 프로바이더 한도를 넘었습니다 (413/415). | 이미지 해상도를 낮추거나 파일 크기를 줄이세요. |
provider_rejected | failed | 모델 제공사 | 아니오 | 프로바이더가 작업을 실패로 보고했습니다 (모더레이션·안전 필터 등). | error 문구가 프로바이더의 사유입니다. 크레딧은 환불됩니다. |
provider_rate_limited | failed | 모델 제공사 | 예 | 프로바이더가 우리 요청을 속도 제한했습니다. | 잠시 후 재시도하세요. 크레딧은 환불됩니다. |
provider_unavailable | failed | 모델 제공사 | 예 | 프로바이더가 5xx를 반환했습니다. | 잠시 후 재시도하세요. 크레딧은 환불됩니다. |
provider_timeout | failed | 모델 제공사 | 예 | 프로바이더가 제한 시간 내에 응답하지 않았습니다. | 재시도하세요. 크레딧은 환불됩니다. |
queue_timeout | failed | 모델 제공사 | 예 | 프로바이더 큐에서 작업이 시작되지 않았습니다. | 재시도하세요. 크레딧은 환불됩니다. |
admission_timeout | failed | 모델 제공사 | 예 | 프로바이더 동시성 한도(admission 큐)에서 대기 시간 상한(기본 600초)을 넘었습니다. 프로바이더 큐에 진입한 뒤 멈춘 queue_timeout과 달리, 이건 프로바이더에 요청을 보내기 전 우리 게이트웨이의 admission 대기열 단계에서 발생합니다. 폴백이 설정된 모델이라면 대기 대신 폴백을 시도했다가 그것도 실패한 경우에도 이 코드가 나오며, 그때는 메시지에 폴백 실패 사유가 함께 담깁니다. | 크레딧은 환불됩니다. `retry_after` 후 재제출 |
admission_drained | failed | Core.Today | 예 | admission 대기열에서 대기하던 중 게이트웨이가 재시작(배포 등)되어 대기 중이던 예약이 취소되었습니다. queue_timeout·admission_timeout과 달리 프로바이더 한도와 무관하게 우리 쪽 재시작이 원인입니다. | 크레딧은 환불됩니다. `retry_after` 후 재제출 |
provider_error | failed | 모델 제공사 | 예 | 분류되지 않은 프로바이더 오류 — 위 코드 중 어디에도 맞지 않을 때의 기본값입니다. | error 문구를 확인하세요. 재시도해도 안전하며 크레딧은 환불됩니다. |
provider_model_not_found | failed | Core.Today | 아니오 | 프로바이더가 우리 쪽 모델 매핑을 거부했습니다 (업스트림 모델 개명 등). | 입력 문제가 아니라 게이트웨이 레지스트리 문제입니다. job_id와 함께 문의해 주세요. 크레딧은 환불됩니다. |
provider_auth_error | failed | Core.Today | 아니오 | 게이트웨이가 프로바이더 인증에 실패했습니다. | 이미 자동 알림이 발송됐습니다. 크레딧은 환불됩니다. |
gateway_execution_timeout | failed | Core.Today | 예 | 게이트웨이 최대 실행 시간을 초과해 작업이 중단됐습니다. | 우리 쪽 문제입니다. 크레딧은 환불되며 재시도해도 안전합니다. |
gateway_internal_error | failed | Core.Today | 예 | 게이트웨이 내부 오류입니다. | 우리 쪽 문제입니다. 크레딧은 환불됩니다. 반복되면 job_id와 함께 문의해 주세요. |
Rate Limits
API 키별 기본 한도 — 초과 시 api_key_rate_limited(AI API) 또는 rate_limited (LLM 게이트웨이)
분당
20/min
시간당
200/hour
일간
1,000/day
팀 단위로 상향 조정할 수 있습니다. 리셀러 워크스페이스의 키는 여러 end-customer 트래픽이 합산 통과하므로 훨씬 높은 상한이 적용되고, 실질 게이트는 아래 end-customer별 한도가 맡습니다.
리셀러 end-customer별 한도 (X-Customer-Id 단위)
요청 속도(customer_rate_limited), 카테고리별 동시 실행 수(customer_concurrency_exceeded, 기본 이미지 10·비디오 5), 분당 LLM 토큰(customer_token_rate_limited)을 지갑별로 설정할 수 있습니다. 현재 사용 현황은 GET /reseller/customers/{id}/concurrency로 확인하세요. 스토리지 용량도 같은 단위로 제한할 수 있습니다 — 초과 시 403 customer_storage_quota_exceeded(지갑 storage_quota > 워크스페이스 default_customer_storage_* 순으로 적용).
IP 기반 제한은 2026-05-05에 폐지됐습니다 — 인증된 요청에는 중복이었고, 사무실·모바일 NAT처럼 IP를 공유하는 정상 사용자를 오탐했기 때문입니다. 429를 받았다면 IP가 아니라 위 한도 중 하나이며, error.code가 어느 쪽인지 알려줍니다.
자주 묻는 질문
Q: API 키를 분실했어요
A: 대시보드에서 기존 키를 삭제하고 새 키를 발급받으세요.
Q: 크레딧이 부족해요
A: 다음날 UTC 자정에 무료 크레딧이 충전됩니다. 또는 충전 코드를 사용하세요.
Q: 예측이 실패했는데 크레딧이 차감됐어요
A: 실패한 예측의 크레딧은 자동으로 환불됩니다.
Q: 스트리밍 응답이 중간에 끊겼는데 에러가 없어요
A: 헤더가 이미 200으로 나간 뒤에는 상태 코드로 실패를 알릴 수 없어, 게이트웨이가 SSE 본문에 data: {"error": {"code": "stream_interrupted", ...}} 프레임을 주입한 뒤 스트림을 닫습니다. content delta만 읽는 클라이언트는 이 프레임을 버리고 뒤따르는 [DONE]을 정상 종료로 착각합니다 — 스트림 루프에서 반드시 error 필드를 확인하세요.
Q: 결과 파일은 얼마나 보관되나요?
A: 팀 플랜에 따라 보관 기간이 다릅니다 (Free 30일, Pro 365일, Team·Enterprise 무기한). 결과 파일의 다운로드 URL은 기본 7일간 유효하며, 만료돼도 파일 자체는 삭제되지 않습니다 — POST /files/sign으로 언제든 새 URL을 재발급받을 수 있습니다.
Q: 이미지 업로드 용량 제한이 있나요?
A: /files/upload-url을 거치는 파일은 파일당 최대 50MB입니다. 반면 요청 본문에 직접 담는 데이터는 AI API 10MB, LLM 게이트웨이 50 MiB 한도를 따릅니다 — 큰 이미지는 업로드 URL을 거쳐 참조로 넘기세요.