오류와 비용
이 문서는 영문 원고를 AI로 번역한 내용이라 표현이 어색할 수 있습니다.
API의 모든 오류는 같은 봉투를 쓰고, 모든 코드는 분기할 수 있는 소문자 토큰입니다. 이 페이지는 Formats 표면의 코드 전부를 한 곳에 모아, 언제 발생하는지로 묶었습니다. run이 생기기 전, run을 읽는 동안, run 자체가 실패할 때, 웹훅을 전달하지 못했을 때. 비용과 요청 한도는 끝에 있습니다.
오류 봉투
| 필드 | 용도 |
|---|---|
code | switch로 분기할 안정적인 토큰. ^[a-z0-9_]+$이며, 문장이 오지 않습니다. |
message | 사람이 읽는 문장이며 바뀔 수 있습니다. 로그에는 남기되, 매칭하지 마세요. |
request_id | x-sume-request-id 헤더로도 옵니다. 지원 요청 시 인용하세요. |
retryable, retry_after_seconds | 같은 요청을 다시 보내면 성공할 수 있는지, 먼저 얼마나 기다릴지. |
next_action | authenticate, fix_input, add_funds, retry_later, poll_status, contact_support, none 중 하나. |
category, stage, public_reason | 대시보드와 알림용 큰 분류. |
details | 코드별 상세: required_scope, workspace_id, violations[], index, status, scope 등. 아래 코드마다 적었습니다. |
HTTP status로 먼저 분기하고, 그다음 code로 분기하세요. 생성 시점의 4xx는 아무것도 실행되지
않았고 아무것도 청구되지 않았다는 뜻이므로, 재시도가 아니라 호출을 고쳐야 합니다.
403 insufficient_scope를 루프에서 재시도하는 것이 가장 흔하고 가장 비싼 실수입니다.
생성 시 오류
POST /v1/formats/{handle}/{slug}/runs와 POST …/bulk-runs. 아무것도 실행되지 않고, 청구도
없으며, 실패한 생성은 Idempotency-Key를 풀어 줍니다.
| Status | error.code | 의미 | 대응 |
|---|---|---|---|
| 400 | invalid_request | 본문에 instruction / input / previous_run_id / attachments 중 하나도 없음; output_schema와 response_format을 둘 다 보냄; input이 object가 아니거나 최상위 키가 64개를 넘거나 2 MiB를 넘음; generation_spend_cap_usd가 0이거나 500 초과; model이 카탈로그에 없음; bulk 본문의 concurrency 또는 items가 잘못됨; 웹훅 URL이 공개 HTTPS가 아님; communication alias가 서로 충돌. | message와 details를 읽으세요. |
| 400 | unknown_parameter | API가 모르는 최상위 필드. thread_id도 여기 해당합니다. details.errors[].suggestion이 의도했을 필드를 알려 줍니다. | 이름을 고치거나 제거하세요. |
| 400 | output_schema_invalid | 스키마가 지원 subset 밖입니다. details.violations[]에 모든 { path, rule, message }가 나열됩니다. | 위반 항목을 각각 고치세요. 지원 스키마를 참고하세요. |
| 400 | invalid_attachment | attachments[] 항목이 잘못됐거나, attachments[]와 input URL이 공유하는 미디어 예산을 넘었습니다. | Format API의 attachment 오류를 참고하세요. |
| 400 | attachment_not_found | 이 워크스페이스에 없는 asset_id. | 업로드하거나 URL을 쓰세요. |
| 400 | previous_run_format_mismatch | previous_run_id가 다른 Format에서 만들어진 run입니다. | 그 Format에서 이어 가세요. |
| 400 | previous_run_not_resumable | 그 run에는 이어 갈 것이 없습니다. details에 previous_run_status, has_thread, artifact_count가 옵니다. | 새 run을 시작하세요. |
| 401 | unauthorized | 키가 없거나, 형식이 잘못됐거나, 폐기됐거나, 다른 호스트의 키이거나, 자격 증명을 두 개 보냈습니다. | 헤더를 고치세요. |
| 402 | insufficient_credits | 워크스페이스 지갑이 이 run을 감당할 수 없습니다. next_action은 add_funds. | 충전하세요. 충전 없이 재시도하면 같은 답이 옵니다. |
| 402 | organization_wallet_not_provisioned | 지갑이 아직 준비되지 않은 조직 워크스페이스. | 관리자가 충전해야 합니다. |
| 403 | insufficient_scope | 키에 formats:write가 없거나(details.required_scope), 서비스 계정 키입니다(details.reason: service_account_format_runs_unsupported). | 스코프를 가진 새 키를 만드세요. 기존 키에는 스코프를 추가할 수 없습니다. |
| 403 | workspace_key_required | 팀 Format인데 개인 키입니다. details.workspace_id가 워크스페이스를 가리킵니다. | 그 워크스페이스에서 키를 만드세요. |
| 404 | format_not_found | 모르는 handle이나 slug, 보관된 Format, 또는 키의 워크스페이스 밖 Format. | 주소와 키를 확인하세요. |
| 404 | previous_run_not_found | previous_run_id가 모르는 값이거나 내 것이 아닙니다. | id를 확인하세요. |
| 409 | format_inactive | Format이 inactive입니다. | 대시보드에서 활성화하세요. |
| 409 | format_api_trigger_disabled | 이 Format의 API 트리거가 꺼져 있습니다. | 대시보드에서 켜세요. |
| 409 | format_run_in_progress | on_active_run: "reject"인데 이미 진행 중인 run이 있습니다. | 기다리거나 reject를 빼세요. |
| 409 | format_not_forkable | Format이 아니라 내장 capability를 주소로 썼습니다. | Formats by Sume나 직접 만든 Format을 호출하세요. |
| 409 | previous_run_not_terminal | 이어 가려는 run이 아직 실행 중입니다. | 폴링한 뒤 다시 호출하세요. |
| 409 | idempotency_conflict | 같은 Idempotency-Key가 다른 본문으로 이미 쓰였습니다. bulk에서는 details.queue_id가 원래 큐를 가리킵니다. | 키 유도 방식을 고치세요. 그대로 재시도하지 마세요. |
| 409 | idempotency_key_in_use | 같은 키의 다른 요청이 진행 중입니다. retryable: true. | 1초쯤 기다렸다가 다시 보내세요. |
| 413 | payload_too_large | 요청 본문이 4 MiB를 넘습니다(details.limit_bytes). | input을 줄이고, 미디어는 URL로 보내세요. |
| 413 | attachment_too_large | 이미지 하나가 30 MB를 넘거나 전체가 500 MB를 넘습니다. | 크기를 줄이세요. |
| 429 | rate_limited | 이 키의 write 예산을 다 썼습니다. error.details.scope는 write. | retry-after만큼 기다리세요. 요청 한도를 참고하세요. |
| 502 | attachment_fetch_failed | Sume가 attachment를 가져오지 못했습니다(details.index). 5xx이지만 입력 문제입니다: next_action은 fix_input. | URL을 공개적으로 접근 가능하게 만드세요. |
| 503 | studio_agent_upstream_unavailable | Sume 쪽 장애. | 같은 Idempotency-Key로 나중에 재시도하세요. |
| 4xx/5xx | format_run_failed_to_start | 더 구체적인 코드가 없는 이유로 run을 시작하지 못했습니다. | message를 읽고 한 번 재시도한 뒤, request_id와 함께 지원에 문의하세요. |
202가 나중에 위 오류로 바뀌는 일은 없습니다. receipt를 받은 뒤의 실패는 receipt 위에
status: "failed"로 옵니다.
읽기 시 오류
GET /v1/format-runs/{run_id}, /status, /result, /events, POST …/cancel,
POST …/webhook/redeliver, GET /v1/format-run-queues/{queue_id}, 그리고 Format 읽기.
| Status | error.code | 의미 | 대응 |
|---|---|---|---|
| 401 | unauthorized | 위와 같습니다. | 헤더를 고치세요. |
| 403 | insufficient_scope | 읽기에는 formats:read, 취소와 redeliver에는 formats:write가 필요합니다. | 새 키를 만드세요. |
| 404 | format_run_not_found | 모르는 run id이거나 다른 소유자의 run. | id와 키를 확인하세요. 볼 수 없는 run은 존재하지 않는 run과 같게 읽힙니다. |
| 404 | format_run_queue_not_found | 모르는 큐이거나 다른 소유자의 큐. | 같습니다. |
| 404 | format_not_found | 위와 같습니다. | 같습니다. |
| 409 | run_not_completed | run이 종료되기 전에 GET …/result를 호출했습니다. details.status가 현재 status이고, retry_after_seconds가 다음 폴링 시점을 제안합니다. | status_url을 폴링한 뒤 result_url을 읽으세요. |
| 409 | webhook_not_configured | webhook_url 없이 만든 run에 redeliver를 호출했습니다. | 다시 보낼 것이 없습니다. |
| 409 | run_not_terminal | run이 아직 실행 중인데 redeliver를 호출했습니다. | 종료 receipt를 기다리세요. |
| 429 | rate_limited | read 예산을 다 썼습니다(details.scope: read). | retry-after만큼 기다리세요. run은 계속 실행됩니다. |
| 503 | studio_agent_upstream_unavailable | Sume 쪽 장애. | 재시도하세요. run은 계속 실행됩니다. |
폴링 루프 안의 429나 503은 일시적입니다. 루프를 포기해도 run이나 그 비용은 멈추지 않으니,
물러났다가 다시 폴링하세요.
run 자체가 실패할 때
끝내지 못한 run은 status: "failed", error: { code, message }, 그리고 대개 더 자세한
output_error와 함께 돌아옵니다. artifacts[]에는 run이 생성한 모든 것이 여전히 나열되고,
output에는 스키마를 만족한 부분 결과가 그대로 실립니다. 실패가 절대 받지 못하는 것은
포인터입니다. primary_output_url이 null이므로 if (run.primary_output_url)은 "완성본이
존재한다"의 안전한 검사로 남습니다.
error.code | 의미 | 대응 |
|---|---|---|
unattended_blocked | 사람 없이는 넘을 수 없는 게이트에 걸렸습니다. 브리프에 맞는 아바타가 없거나, 채팅이었다면 물어봤을 입력이 빠진 경우. message는 그대로 보여 줘도 되게 쓰여 있습니다. | 입력이나 브리프를 고치고, 새 Idempotency-Key로 재시도하세요. |
output_schema_unsatisfied | run은 끝났지만 결과가 output_schema에 맞지 않았거나, 만들지 않은 미디어를 참조했습니다. details.rejected_urls[] 또는 details.violations[], 그리고 미디어 종류별 harvested 수. | details.harvested를 스키마의 필수 항목과 비교하세요. 대개 Format이 만들지 않는 파일을 요구하는 스키마입니다. nullable로 풀거나 instruction을 바꾸세요. |
deliverable_missing | Format이 미디어를 만든다고 선언했는데(io.output_kind) 이 run은 하나도 만들지 않았습니다. | 재시도하세요. 반복되면 입력이 레시피가 기대하는 것이 아닙니다. |
primary_output_missing | 결과는 스키마를 만족했지만, 지정한 primary_output_key가 비어 있습니다. output에 부분 결과가 실립니다. | run을 이어 가서 빈 곳을 채우거나 재시도하세요. |
agent_reported_failure | run 자신이 제출한 return_format_output이 "전달하지 못했다"고 말했습니다. 명시적 실패 payload, failed / stand-in으로 표시된 미디어 슬롯, 또는 Format이 선언한 산출물이 아닌 primary(video 키 아래의 오디오나 정지 이미지). output에는 실제로 만들어진 것의 ledger가 실리고 primary_output_url은 null입니다. | details.reason과 output을 읽으세요. output의 클립은 실제 결과이며 재시도해도 다시 생성되지 않습니다. run을 이어 가거나 새 Idempotency-Key로 다시 실행하세요. |
incomplete_assembly | 생성 job이 아직 끝나지 않은 채 run이 시간 한도에 닿아, 전달된 미디어가 지불한 전부가 아닙니다. details.pending_job_count와 details.pending_jobs[]가 그 job들을 가리키고, 스키마가 허용하면 부분 ledger가 output에 실립니다. | previous_run_id로 run을 이어 가세요. 끝난 클립은 스레드에 있고 다시 생성되지 않습니다. |
output_extraction_failed | 투영 자체를 실행하지 못했습니다. details.reason: harvest_unavailable은 run이 마무리되는 동안 미디어를 읽지 못했다는 뜻이며, status는 completed로 남고 다음 읽기에서 receipt가 채워집니다. details.reason: harvest_threw는 run이 끝난 뒤 호스트의 harvest 자체가 크래시했다는 뜻입니다. run은 failed가 되고 details.thrown에 던져진 프레임과 빌드가 실리며, ledger에 Format이 선언한 미디어가 하나도 없는 run은 대신 deliverable_missing을 보고합니다. | harvest_unavailable: run을 한 번 더 읽고, 계속되면 새 키로 재시도하세요. harvest_threw: 호스트 결함입니다 — run id를 알려 주세요. 스레드의 클립은 실제 결과이며 재시도해도 다시 생성되지 않습니다. |
mcp_unavailable | 이 run에 필요한 턴별 Sume MCP 도구가 붙지 않아, 도구 없는 턴을 실행하는 대신 호스트가 모델 실행 전에 run을 실패시켰습니다(#7378). details.retryable은 true, details.charged는 false입니다 — 생성이 실행되지 않았고 과금도 없습니다. | 새 Idempotency-Key로 재시도하세요. 반복되면 요청이 아니라 도구가 다운된 것입니다. |
provider_unavailable | 모델 제공자 스트림이 끊기고 재연결 횟수를 다 쓴 뒤에도 run이 완성본을 만들지 못했습니다. 입력 때문이 아닙니다. details.retryable은 true입니다. | 새 Idempotency-Key로 재시도하세요. 끝난 클립은 스레드에 있고 다시 생성되지 않습니다. |
format_run_failed | 일반 실패. | message를 읽으세요. cap을 넘어 쓰려던 run도 여기로 오므로, 브리프를 키우기 전에 usage.billable_amount_usd_micros와 usage.generation_spend_cap_usd_micros를 비교하세요. |
이 집합은 열려 있다고 보세요. 새 코드가 추가될 수 있으니 아는 것만 처리하고 나머지는 그대로
통과시키세요. 실패한 run은 새 Idempotency-Key로 재시도하세요. 옛 키는 이미 받은 receipt에
묶여 있습니다. 실패가 클립을 남겼다면 새 run보다 run 이어 가기를 택하세요.
웹훅으로는 같은 run이 status: "ERROR", outcome: "error", 그리고 payload.error.code를
그대로 비추는 error.code와 함께 도착합니다. 완료됐지만 스키마를 채우지 못한 run은
status: "OK", outcome: "degraded"로 도착합니다. 실제 미디어는 있고, output은 null입니다.
웹훅 전달 실패
전달 결과는 run을 절대 바꾸지 않습니다. 모든 receipt의 webhook_delivery 블록이 무슨 일이
있었는지 말해 줍니다.
webhook_delivery.status | 의미 | 대응 |
|---|---|---|
retrying | 시도가 실패했고 next_attempt_at이 다음 시도 시각입니다. 엔드포인트의 HTTP 429/503은 Retry-After를 최대 1시간까지 존중합니다. | last_status_code가 고칠 수 있는 것이 아니라면 할 일이 없습니다. |
failed, exhausted | 열 번의 시도가 거부되거나, 시간 초과(각 10초)되거나, 리다이렉트되거나, URL이 재검증에 실패했습니다. last_status_code와 last_error가 이유를 말합니다. | result_url에서 receipt를 읽고, 엔드포인트를 고친 뒤 POST …/webhook/redeliver로 다시 보내세요. |
payload: null인 봉투 | receipt가 1 MiB를 넘었습니다. error.code는 payload_too_large이고 error.result_url이 가져올 곳을 말합니다. status는 여전히 run의 실제 결과를 보고합니다. | result_url을 가져오세요. payload가 object라고 가정한 handler는 가장 큰 run에서 터집니다. |
전체 전달 규칙: 실행과 결과.
크레딧과 비용
run은 키가 속한 워크스페이스에서 비용을 씁니다. 두 개의 게이트가 서로 다른 시점에 적용됩니다.
| 게이트 | 시점 | 실패 시 |
|---|---|---|
| 지갑 | 생성 시. 워크스페이스가 run을 감당할 수 있어야 합니다. | 402 insufficient_credits(next_action: add_funds) 또는 402 organization_wallet_not_provisioned. 아무것도 실행되지 않았습니다. |
| Spend cap | run 도중. run은 유효 cap을 넘어 쓸 수 없습니다. | run이 failed로 끝나고, usage가 cap에 얼마나 가까웠는지 보여 줍니다. |
cap은 여러분이 쥔 제어 수단입니다. 모든 Format이 cap을 하나 갖고 있고(Format의
generation_spend_cap_usd_micros; 지정한 적이 없으면 $400), 요청의 generation_spend_cap_usd가
이 run만의 천장을 플랫폼 최대 $500까지 지정합니다. Format cap보다 큰 값도 그대로 적용되고,
null은 $500으로 실행하며, 0은 거부됩니다. 프로덕션의 긴 영상 run은 보통 $120 안팎의 cap으로
만들어지고, 씬 하나 재시도는 몇 달러면 됩니다. 자세한 내용: Spend caps.
청구되는 것은 계량된 생성(영상, 이미지, 아바타, 음성, 타임라인 작업)이며,
API 요금 페이지의 요율을 따릅니다. receipt는 이것을
usage.billable_amount_usd_micros로 보고합니다. run이 진행되는 동안 올라가고, 예약된 금액과
확정된 금액을 모두 세며, run이 종료되면 정산됩니다. 에이전트 자체의 LLM 턴은 제외되므로 run의
총비용은 아니고, 청구서가 아니라 receipt 숫자입니다. GET /v1/usage와
GET /v1/balance가 청구 기록입니다. usage가 null이면 비용을 읽지 못한 것이며, 0과는
다릅니다.
취소나 실패 전에 끝난 생성은 청구되며, 뒤 단계가 실패해도 환불되지 않습니다. 생성 시점의
4xx, 멱등 200 재생, skipped run은 비용이 들지 않습니다.
요청 한도
모든 키는 워크스페이스 플랜에 따라 /v1 전체에 걸친 분당 요청 예산을 갖습니다. 읽기와 쓰기는
예산이 분리되어 있고, 읽기는 쓰기 숫자의 40배를 받으므로 폴링이 여러분의 생성 요청을 굶기지
않습니다.
| 플랜 | 분당 쓰기 | 분당 읽기 |
|---|---|---|
| Free | 120 | 4800 |
| Pro | 300 | 12000 |
| Startup | 600 | 24000 |
| Scale | 1200 | 48000 |
| Enterprise | 계약값. 준비 전까지는 Scale | 계약값 |
읽기는 모든 GET입니다. receipt, status_url, events_url, result_url, Format과 run
목록. 쓰기는 나머지 전부입니다. run과 큐 생성, 취소, redeliver.
모든 응답에 현재 상태가 실리고, 429는 어느 예산에서 나왔는지 알려 줍니다.
| 헤더 | 의미 |
|---|---|
ratelimit-limit | 이 요청이 쓴 예산 기준으로, 현재 창에서 허용되는 요청 수. |
ratelimit-remaining | 그 창에 남은 요청 수. |
ratelimit-reset | 창이 초기화되기까지의 초. |
retry-after | 429에 실리는 대기 초. error.details.scope는 read 또는 write. |
직접 요청을 세지 말고 헤더에 맞춰 속도를 조절하세요. 요청 속도는 생성 용량이 아닙니다. 동시에 실행되는 생성 수는 플랜의 concurrency 한도가 정하며, 요청 속도를 올려도 늘어나지 않습니다.
도움 받기
모든 응답에 x-sume-request-id가, 모든 receipt에 request_id가 실립니다. 문의할 때 이 값과
run id, error.code를 인용하세요. API 키, 서명 시크릿, 원본 미디어 URL은 보내지 마세요.

