Skip to Content

오류와 재시도

오류 응답 형식

오류는 항상 아래 envelope로 옵니다.

{ "error": { "code": "RATE_LIMITED", "message": "Request limit exceeded", "retryable": true, "request_id": "0b7b8f0e-0000-4000-8000-000000000010", "details": {"reset_at": "2026-10-05T09:01:00+00:00"} } }
필드설명
code기계가 읽는 오류 코드. 분기에는 message가 아니라 이 값을 쓰세요.
message사람이 읽는 영어 설명. 바뀔 수 있습니다.
retryable같은 요청을 다시 보내면 성공할 수 있는지 서버가 알려 주는 값
request_id이 요청의 ID. 문의할 때 알려 주세요.
details코드에 따른 추가 정보. 예를 들어 reset_at, state_url
  • 모든 응답에 X-Request-Id 헤더가 있고 본문의 request_id와 같습니다. 서버가 요청마다 새로 발급합니다.
  • 429와 일부 503에는 Retry-After(초) 헤더가 있습니다.
  • 모든 응답은 Cache-Control: no-store입니다.
  • 요청에 X-Correlation-Id를 넣으면 호출자 쪽 추적에 쓸 수 있습니다. 서버가 만드는 request_id와는 별개입니다.
  • 접수에 성공(202)한 Turn이나 Run이 나중에 실패하는 것은 HTTP 오류가 아닙니다. 상세 조회 응답의 error.code로 확인합니다.

재시도 원칙

  1. retryable이 true인 오류와 네트워크 오류(연결 끊김, 시간 초과)만 재시도합니다.
  2. Retry-After가 있으면 그 시간만큼 기다립니다. 없으면 지수 백오프에 무작위 지연을 더합니다.
  3. 생성, 입력, 취소, 업로드 요청은 재시도할 때 같은 Idempotency-Key와 같은 본문을 보냅니다. 이미 접수된 요청이면 같은 receipt가 돌아오므로 중복 실행이 없습니다.
  4. retryable이 false인 오류는 같은 요청을 그대로 다시 보내도 같은 결과입니다. 요청을 고치거나 원인을 해결하세요.
  5. 응답을 못 받은 요청을 새 키로 다시 보내면 같은 일이 두 번 실행될 수 있습니다. 재시도에는 키를 바꾸지 마세요.
  6. 재시도 횟수와 총 대기 시간에 상한을 두세요.
def post_with_retry(url: str, key: str, body: dict, attempts: int = 5) -> httpx.Response: for attempt in range(attempts): try: response = httpx.post(url, headers={**AUTH, "Idempotency-Key": key}, json=body, timeout=30) except httpx.TransportError: response = None if response is not None and response.status_code < 400: return response try: error = response.json().get("error", {}) if response is not None else {} except ValueError: # a proxy may answer 502/503/504 without the JSON envelope error = {"retryable": response.status_code in (429, 502, 503, 504)} if response is not None and not error.get("retryable"): response.raise_for_status() delay = float(response.headers.get("Retry-After", 0)) if response is not None else 0 time.sleep(delay or min(30, 0.5 * 2 ** attempt)) raise RuntimeError("gave up after retries")

HTTP 상태별 의미

상태의미
200, 201성공. 조회와 close는 200, 파일 업로드는 201
202접수됨. 결과는 나중에 조회합니다.
400형식이 잘못된 cursor, 상관 ID 같은 요청 오류
401키 문제. 폐기된 키는 재시도해도 소용없습니다.
402SU 잔액 또는 예산 문제
403scope나 권한 부족
404없거나 권한 밖인 자원. 존재 여부를 알려 주지 않습니다.
409현재 상태와 충돌. 예를 들어 이미 실행 중이거나 키가 충돌한 경우
410보존 기간이 지나 내용이 없는 경우
413, 415크기 한도 초과, 지원하지 않는 형식
422값이 허용 범위나 schema를 벗어남
429호출 속도 또는 동시 실행 한도
500, 503서버 쪽 문제. retryable과 Retry-After를 따르세요.

오류 코드 표

아래 표는 호출자가 받을 수 있는 공개 코드입니다. HTTP 상태가 -인 코드는 HTTP 응답이 아니라 Turn이나 Run 상세의 error.code로만 보이며, 이때 retryable은 false입니다. retryable은 같은 요청을 다시 보내는 것에 대한 값이라 끝난 실행에서는 늘 false입니다. 새 실행을 만들어도 되는지는 아래 “실패한 실행 뒤 다음 행동” 표를 따르세요. SESSION_SANDBOX_UNAVAILABLE처럼 HTTP 응답과 실행 상세에 모두 쓰이는 코드는 한 행에 HTTP 응답일 때의 상태와 retryable을 적고, 실행 상세에서 보일 때의 뜻을 의미 칸에 함께 적었습니다. 내부에서만 쓰는 코드는 싣지 않았습니다. 새 코드가 추가될 수 있으니 모르는 코드는 retryable과 HTTP 상태로 처리하세요.

코드HTTP 상태retryable의미
NOT_FOUND404false없거나 권한 밖인 자원입니다. 허용되지 않은 Project에서는 모든 경로가 이 코드입니다.
HTTP_ERROR4xxfalse경로나 메서드가 맞지 않는 등 라우팅 단계의 거절입니다.
INVALID_API_KEY401false키가 없거나 형식이 틀렸거나 폐기, 만료되었습니다.
INSUFFICIENT_SCOPE403false키에 이 작업의 scope가 없습니다.
ACTING_FORBIDDEN403false대리 접근 헤더나 파라미터는 허용되지 않습니다.
WORKFLOW_DATA_DENIED403false워크플로가 게시 때 받은 데이터 권한 밖의 데이터를 쓰려 했습니다.
ACTION_NOT_RESOLVABLE_BY_CALLER403false해당 승인을 해소할 명시적 actions:approve 위임이 없습니다. 업무 준비의 범위 확인 답이면 works:approve 위임이 없는 것입니다.
ACTION_CONTENT_CHANGED409false승인 내용이 바뀌었습니다. 다시 조회하고 사람의 결정을 받으세요.
APPROVAL_CONTENT_UNAVAILABLE409false승인 자료를 읽을 수 없거나 READ 권한이 부족합니다.
APPROVAL_CONTENT_TOO_LARGE413false승인 자료가 100행 또는 256KiB를 초과합니다.
INVALID_INPUT400, 422false요청 본문이나 입력 형식이 잘못되었습니다. 선언되지 않은 필드도 여기에 해당합니다.
LIMIT_OUT_OF_RANGE422falselimits 값이 허용 범위를 벗어났습니다. 상한을 넘는 값을 조용히 줄이지 않습니다.
INVALID_CURSOR400falseafter나 Last-Event-ID가 이 자원의 cursor가 아니거나 서로 다릅니다.
INVALID_CORRELATION_ID400falseX-Correlation-Id 형식이 틀렸습니다.
INVALID_IDEMPOTENCY_KEY422falseIdempotency-Key가 없거나 1~256바이트가 아닙니다.
IDEMPOTENCY_CONFLICT409false같은 Idempotency-Key를 다른 본문이나 다른 파일로 보냈습니다. 새 요청에는 새 키를 쓰세요.
INPUT_TOO_LARGE413falseJSON 요청 본문이 64KiB를 넘었습니다.
FILE_TOO_LARGE413false업로드 파일이 20MiB를 넘었습니다.
UNSUPPORTED_MEDIA_TYPE415falseJSON이 아니거나 압축된 본문입니다.
INVALID_FILENAME422false파일 이름이 비었거나 255바이트를 넘거나, 경로 구분자(슬래시, 역슬래시)나 제어 문자를 담고 있습니다. 업로드 응답으로 받았다면 이름을 고쳐 다시 올리세요. Turn이나 Run 상세의 error.code로 보이면 실행 중 AI 직원이 만든 결과 파일의 이름이 이 규칙에 맞지 않아 실행이 실패한 것이며 이때 retryable은 false입니다.
UNSUPPORTED_FILE_TYPE415false파일 이름의 확장자와 MIME 형식이 허용된 짝이 아니거나, 내용이 그 형식이 아니거나 안전하지 않습니다(예: 매크로가 든 문서, 암호화된 PDF). 업로드할 때, 또는 Deployment가 받지 않는 형식의 파일을 Turn 입력에 넣었을 때 옵니다. 허용 형식은 한도와 데이터에 있습니다. Turn이나 Run 상세의 error.code로 보이면 실행 중 만든 결과 파일이 허용되지 않는 형식이어서 실행이 실패한 것이며 이때 retryable은 false입니다.
OUTPUT_SCHEMA_MISMATCH422false값이 발행 때 정한 형식이나 schema와 맞지 않습니다. HTTP 응답으로 받았다면 Run 생성 요청의 input이 워크플로의 input_schema와 맞지 않는 것입니다. Turn이나 Run 상세의 error.code로 보이면 결과가 발행 때 정한 결과 계약과 맞지 않아 실행이 실패한 것이며 이때 retryable은 false입니다. JSON 결과의 schema 불일치는 실행 중 AI 직원에게 먼저 돌려줘 고칠 기회를 주고, 고치지 못한 채 끝나면 이 코드가 됩니다.
OUTPUT_LIMIT_EXCEEDED422false값이 크기나 개수 한도를 넘었습니다. HTTP 응답으로 받았다면 Run 생성 요청의 input이 JSON 한도(깊이 16, 배열 원소 합 10,000개)를 넘은 것입니다. Turn이나 Run 상세의 error.code로 보이면 결과가 크기나 개수 한도를 넘어 실행이 실패한 것이며 이때 retryable은 false입니다. 조용히 자르지 않고 실패로 닫습니다.
TOO_MANY_FILES422false입력 파일이 20개를 넘었거나 같은 파일을 중복해서 넣었습니다.
FILE_EXPIRED410false입력 파일이 아직 준비되지 않았거나 만료되었습니다. 다시 업로드하세요.
ARTIFACT_EXPIRED410false보존 기간이 지나 결과 파일을 더는 받을 수 없습니다. 결과 목록에서는 그 항목이 availability: EXPIRED와 이 error.code로 보입니다.
PROJECT_STORAGE_LIMIT413falseProject 파일 보관량(500MiB) 또는 조직의 남은 용량을 넘었습니다.
RUN_STORAGE_LIMIT413false한 실행의 파일 합계(100MiB)를 넘었습니다.
REVISION_CONFLICT409false읽은 뒤 업무나 준비가 바뀌었습니다. 다시 조회해 지금 상태로 보내세요.
PREPARATION_IN_PROGRESS409false같은 업무의 준비가 이미 진행 중입니다. details.preparation_id의 준비를 조회하세요.
INVALID_TRANSITION409false준비가 지금 상태에서 이 요청을 받지 않습니다. 예를 들어 끝났거나 확인 기한이 지났습니다.
QUESTION_NOT_FOUND409false열려 있지 않은 준비 질문입니다. 다시 조회하세요.
PACKAGE_CHANGED409false사람이 확인한 구성 후보가 바뀌었습니다. 새 질문을 다시 보여 주고 확인받으세요.
INVALID_SPEC422false업무 명세가 규칙에 맞지 않습니다. details.reason을 보세요.
INVALID_REQUEST422false업무 준비 요청이 규칙에 맞지 않습니다. details.reason을 보세요.
SESSION_BUSY409falseSession에 이미 실행 중인 Turn이 있습니다. 종결을 확인한 뒤 보내세요.
SESSION_CLOSED409false닫힌 Session은 입력과 파일을 받지 않습니다.
SESSION_EXPIRED410falseSession 내용의 보존 기간이 끝났습니다.
SESSION_UPDATING503trueSession을 갱신하는 중입니다. 같은 Idempotency-Key로 다시 보내세요.
SESSION_SANDBOX_UNAVAILABLE503trueSession 실행 환경을 지금 준비하지 못했습니다. HTTP 응답으로 받았다면 잠시 뒤 다시 시도하세요. Turn이나 Run 상세의 error.code로 보이면 작업을 시작하기 전, 실행 환경 준비 단계가 시간 안에 끝나지 않아 Turn이 실패한 것이며 이때 retryable은 false입니다. 워크플로 단계에서 생기면 Run도 대개 이 코드로 끝납니다. 다만 준비 중 보낸 요청의 결과를 확인하지 못했으면 Run은 사용량이 확인될 때까지 EXTERNAL_EFFECT_UNKNOWN으로 남습니다. 앞선 실행을 기다리다 시간이 다 된 경우는 지금처럼 EXECUTION_TIMEOUT입니다. 요청 내용 문제가 아니니 잠시 뒤 새 실행을 만드세요.
DEPLOYMENT_UNAVAILABLE409false이 Deployment는 지금 이 작업을 받을 수 없습니다. 상태를 확인하세요.
WORKFLOW_UNAVAILABLE409false워크플로가 게시되어 있지 않거나 멈춰 있거나, 메일로만 시작할 수 있는 워크플로처럼 API로 시작할 수 없어서 Run 생성(POST /v1/workflows/{workflow_id}/runs)을 받지 않습니다. GET /v1/workflows/{workflow_id}는 이 상태를 오류 응답이 아니라 200 본문의 available: false와 error.code로 알려 줍니다. 실행 중에 워크플로가 멈추면 Run은 CANCELED로 끝나고 Run 상세의 error.code가 이 값입니다. 발행한 사람이 워크플로를 다시 게시하거나 켠 뒤에 시도하세요.
WORKFLOW_MANAGED_SESSION409false워크플로가 쓰는 내부 Session입니다. Run 경로를 사용하세요.
RUN_TERMINAL409false이미 결과가 확정된 Run입니다.
ACTION_EXPIRED409false질문의 답변 기한이 지났습니다.
ACTION_CANCELED409false실행이 더는 이 질문을 기다리지 않습니다.
MINIMUM_SU_REQUIRED402false파일 작업에는 계정 잔액이 50 SU 이상이어야 합니다. 50 SU를 차감하는 것은 아닙니다.
INSUFFICIENT_SU402false사용 가능한 SU가 부족합니다.
BUDGET_EXCEEDED402false이 실행의 예산이 소진되었거나 닫혔습니다.
PROJECT_BUDGET_EXCEEDED402trueProject의 일 또는 월 지출 한도를 넘었습니다. 한도 창이 지나면 다시 가능합니다.
RATE_LIMITED429true호출 속도 한도를 넘었습니다. Retry-After만큼 기다리세요.
CONCURRENCY_LIMIT429trueProject의 동시 실행 한도를 넘었습니다. 실행이 끝난 뒤 다시 시도하세요.
SOURCE_UNAVAILABLE503true워크플로 입력을 확인할 조직 데이터 저장소에 지금 연결할 수 없어 Run 생성(POST /v1/workflows/{workflow_id}/runs)을 받지 않았습니다. Run은 만들어지지 않았습니다. 잠시 뒤 같은 Idempotency-Key로 다시 보내세요. 계속되면 발행한 사람에게 알리세요.
BILLING_UNAVAILABLE503true결제 계정을 지금 확인하지 못했습니다. 잠시 뒤 다시 시도하세요.
ARTIFACT_NOT_READY409true파일이 아직 준비되지 않았습니다. 잠시 뒤 다시 시도하세요.
ARTIFACT_UNAVAILABLE503true보관된 파일을 지금 읽지 못합니다. 다시 시도하세요.
STORAGE_UNAVAILABLE503true파일 저장소를 지금 쓸 수 없습니다. 다시 시도하세요.
EVENT_CURSOR_EXPIRED410false이벤트 cursor가 만료되었습니다. details의 주소로 복구하세요.
OUTPUT_MANIFEST_UNAVAILABLE503true결과 목록을 지금 읽지 못합니다. 다시 시도하세요.
INTERNAL_ERROR500false서버 내부 오류입니다. request_id와 함께 문의하세요.
EXECUTION_TIMEOUT-falseTurn이 실행 시간 한도를 넘어 실패했습니다.
QUEUE_TIMEOUT-false대기 시간 한도 안에 실행이 시작되지 않아 만료되었습니다.
RECOVERY_EXHAUSTED-false서버가 복구를 여러 번 시도했지만 끝내지 못했습니다.
RUN_DEADLINE_EXCEEDED-falseRun 전체 기한에 먼저 닿아 만료되었습니다.
EXTERNAL_EFFECT_UNKNOWN-false외부에 쓴 작업의 결과를 확인할 수 없어 멈췄습니다. 결과를 직접 확인하세요. 자동으로 다시 실행하지 않습니다.
ACTION_REQUIRED_UNSUPPORTED-false사람의 답이나 승인이 필요해졌지만 현재 API에서 지원하지 않아 실패했습니다.
CAPABILITY_DENIED-false발행 때 허용하지 않은 도구나 기능을 쓰려 했습니다.
SESSION_RESOURCES_NOT_READY-false발행본이 허용한 도구 중 이 단계에서 아직 지원하지 않는 것을 호출했습니다.
ARTIFACT_PREPARATION_TIMEOUT-false결과 파일 준비가 기한을 넘었습니다.
ARTIFACT_PREPARATION_FAILED-false결과 파일이 실행이 끝날 때 준비되어 있지 않거나 이미 만료되어 결과로 내지 못했습니다.
OUTPUT_URL_INVALID-falseURL 결과가 공개 HTTPS 주소가 아닙니다. 내부망 주소와 로그인 정보, 서명, 토큰이 든 주소도 거절합니다.
OUTPUT_CONTAINS_CREDENTIALS-false결과(값, 파일 이름, 파일 내용, URL)에 키나 비밀번호 같은 자격 증명 패턴이 들어 있어 내보내지 않았습니다.
OUTPUT_PATH_DENIED-falseSession 첨부 폴더 밖의 파일을 결과로 내보내려 했습니다.
OUTPUT_MISSING-false발행 때 필수로 정한 결과가 만들어지지 않았습니다.
EXECUTION_FAILED-false예기치 않은 오류로 실행이 실패했습니다.
CANCELED-false취소 요청으로 실행이 멈췄습니다.
AUTHORIZATION_REVOKED-false실행 중 키가 폐기, 만료되었거나 scope, Deployment, 발행본이 쓰는 계정 연결을 쓸 수 없게 되어 취소되었습니다.
SESSION_DELETED-falseSession이 삭제되어 진행 중이던 Turn이 취소되었습니다.
RUNTIME_CONTEXT_MISMATCH-falseSession 상태가 실행할 수 있는 상태와 맞지 않아 실패했습니다.
USAGE_PENDING-false앞선 사용량 정산을 확인하지 못해 실행을 이어 가지 못했습니다.

실패한 실행 뒤 다음 행동

Turn이나 Run이 FAILED, CANCELED, EXPIRED로 끝나면 그 실행은 다시 살아나지 않습니다. 다시 하려면 새 Idempotency-Key로 새 Turn이나 Run을 만듭니다. 응답을 받지 못한 요청을 같은 키로 다시 보내는 위의 재시도와는 다릅니다. 끝난 실행의 키를 그대로 쓰면 끝난 실행의 receipt가 다시 돌아옵니다.

AI 도구가 호출을 대신하는 경우에도 아래 순서를 지키세요. 새 실행은 비용이 다시 듭니다.

판단코드다음 행동
잠시 뒤 한 번 더QUEUE_TIMEOUT, RECOVERY_EXHAUSTED, EXECUTION_FAILED, USAGE_PENDING, ARTIFACT_PREPARATION_TIMEOUT, ARTIFACT_PREPARATION_FAILED, SESSION_SANDBOX_UNAVAILABLE시간을 두고 같은 입력으로 새 실행을 한 번 만듭니다. 같은 코드로 다시 끝나면 멈추고 실행 ID와 함께 문의합니다.
조건을 바꾼 뒤EXECUTION_TIMEOUT, RUN_DEADLINE_EXCEEDED, BUDGET_EXCEEDED, INSUFFICIENT_SU입력을 줄이거나 나누고, 한도와 데이터의 허용 범위 안에서 기한이나 예산을 늘리거나 SU를 충전한 뒤 새 실행을 만듭니다. 같은 조건으로 바로 다시 보내지 않습니다.
발행 설정 문제OUTPUT_SCHEMA_MISMATCH, OUTPUT_LIMIT_EXCEEDED, OUTPUT_MISSING, OUTPUT_PATH_DENIED, CAPABILITY_DENIED, SESSION_RESOURCES_NOT_READY, ACTION_REQUIRED_UNSUPPORTED, WORKFLOW_UNAVAILABLE호출자가 고칠 수 없는 경우가 많습니다. 같은 입력을 반복하지 말고 Deployment나 워크플로를 발행한 사람에게 알립니다. 입력 때문에 결과가 한도를 넘었다면 입력을 줄여 새 실행을 만듭니다. WORKFLOW_UNAVAILABLE은 워크플로가 다시 게시되거나 켜진 뒤에만 새 Run을 만듭니다.
결과 내용 확인OUTPUT_URL_INVALID, OUTPUT_CONTAINS_CREDENTIALS, INVALID_FILENAME, UNSUPPORTED_FILE_TYPEAI 직원이 만든 결과가 공개 결과 규칙에 맞지 않았습니다. 입력이 내부 주소, 자격 증명, 허용되지 않는 파일 형식이나 이름을 결과에 넣으라고 요구하지 않았는지 확인하고, 고친 입력으로 새 실행을 한 번 만듭니다. 같은 코드로 다시 끝나면 Deployment나 워크플로를 발행한 사람에게 알립니다.
권한 확인AUTHORIZATION_REVOKED키, scope, Deployment 상태와 발행한 사람의 계정 연결을 확인합니다. 새 키나 권한을 받거나 연결이 복구된 뒤에만 새 실행을 만듭니다.
새 Session에서RUNTIME_CONTEXT_MISMATCH새 Session을 만들어 실행합니다. 반복되면 실행 ID와 함께 문의합니다.
다시 실행하지 않음EXTERNAL_EFFECT_UNKNOWN외부 시스템에 이미 쓰였을 수 있습니다. 그 시스템에서 결과를 직접 확인하기 전에는 새 실행을 만들지 않습니다.
의도한 종료CANCELED, SESSION_DELETED취소나 삭제를 요청한 쪽의 결정입니다. 그 결정이 바뀐 경우에만 새 실행을 만듭니다.

표에 없는 코드는 다시 실행하지 말고 멈춘 뒤 사람에게 알리세요.

실행 중 AI 직원이 낸 결과가 공개 결과 규칙에 걸리면 그 실행은 그 자리에서 실패로 끝납니다. 결과 형식 오류 가운데 JSON 결과의 schema 불일치만 실행 중 AI 직원에게 돌려줘 고치게 합니다. 실패하지 않고 일부 결과만 받는 워크플로(PARTIALLY_SUCCEEDED)에서는 실패한 결과 항목의 error.code에 같은 코드가 남습니다.

조직 업무 준비의 실패도 HTTP 오류가 아닙니다. 사유는 준비의 reason_codes에 있고, 다음 행동은 조직 업무 만들기에 있습니다.