409 Conflict 오류: 의미와 재시도해야 할 때
409 Conflict는 요청이 서버의 현재 상태와 충돌했다는 뜻입니다. 오류 코드를 읽고 다시 보낼지, Job을 기다릴지, 호출을 고칠지 정하세요.

409 Conflict는 요청의 형식이 잘못됐다는 뜻이 아니라, 요청이 대상의 현재 상태와 충돌했다는 뜻입니다. 다시 보내는 것은 그 상태가 바뀐 뒤에야 도움이 되므로, 먼저 오류 코드를 읽으세요. 어떤 409는 1초쯤이면 풀리고, 어떤 409는 Job이 끝나야 풀리며, 어떤 409는 요청을 바꿔야 풀립니다.
HTTP 정의는 MDN의 409 Conflict 페이지에서 인용했고, Sume 코드는 오류와 비용 (영문), Format 호출하기 (영문), Job과 결과 (영문) 문서에서 가져왔습니다. 모두 2026-09-27에 확인했습니다.
409 Conflict는 무슨 뜻인가요?
MDN은 이를 요청이 대상 리소스의 현재 상태와 충돌하는 것으로 정의합니다. 예로는 서버에 있는 파일보다 오래된 파일을 업로드하는 경우부터, 작업 두 개를 동시에 실행하기를 거부하는 서버까지 있습니다.
Request failed with status code 409 같은 오류 문구는 axios가 상태 코드 때문에 거부한 응답을 표현하는 방식이고, 409 Client Error: Conflict for url은 Python Requests가 raise_for_status()에서 만드는 메시지입니다. 둘 다 이유는 말해 주지 않습니다. 이유는 응답 본문에 있습니다. axios는 이를 error.response.data에 넣고, Requests에서는 response.json()을 읽으면 됩니다.
409는 재시도해야 하나요?
충돌이 풀린 뒤에만 재시도하세요. Sume 코드 하나는 1초쯤이면 풀리고, 다른 코드는 실행이 끝나야 풀리며, 어떤 코드는 요청을 바꾸기 전까지 절대 풀리지 않습니다. Sume에서는 무엇이 충돌을 푸는지에 따라 코드를 나눠 보세요.
| 풀리는 조건 | `error.code` | 할 일 |
|---|---|---|
| 약 1초 | idempotency_key_in_use | 같은 키의 다른 요청이 진행 중입니다. 1초쯤 기다렸다가 다시 보내 원래 실행을 받으세요. |
| 실행 종료 | run_not_completed | result_url을 너무 일찍 읽었습니다. status_url을 폴링한 뒤 결과를 읽으세요. |
| 실행 종료 | previous_run_not_terminal, run_not_terminal | 아직 진행 중인 실행을 이어 가거나 재전달하려고 했습니다. 폴링한 뒤 다시 호출하세요. |
| 다른 실행의 종료 | format_run_in_progress, action_run_in_progress | 실행이 활성인 동안 on_active_run: "reject"를 보냈습니다. 기다리거나 reject를 빼세요. |
| 없음: 요청을 고쳐야 함 | idempotency_conflict | 그 키가 이미 다른 본문으로 쓰였습니다. 키를 만드는 방식을 고치고, 그대로 다시 보내지 마세요. |
| 없음: 소유자가 조치해야 함 | format_inactive, format_api_trigger_disabled | Format 소유자가 Format 페이지의 API 탭에서 Format을 Inactive로 설정했거나 API 호출을 껐습니다. |
| 없음: 이미 늦음 | job_generation_already_started | 생성이 시작된 뒤에 취소 요청이 왔습니다. Job은 끝까지 실행됩니다. |
| 새로 읽기 | format_content_sha_mismatch, format_package_sha_mismatch | 누군가 Format 패키지에 먼저 커밋했습니다. 다시 읽고 현재 sha로 재시도하세요. |
같은 Idempotency-Key가 왜 409를 반환하나요?
그 키로 보낸 첫 요청이 아직 진행 중이거나(위의 idempotency_key_in_use), 본문이 바뀌었기 때문입니다. 같은 키와 같은 본문을 재전송하면 원래 실행이 200으로 돌아옵니다. 같은 키에 다른 본문(다른 instruction이나 첨부 목록 포함)을 보내면 409 idempotency_conflict이며, 아무것도 실행되지 않습니다. 현재 코드에서는 비교 대상에 communication도 들어가므로, webhook_url을 새로 바꿔도 다른 본문이 됩니다. 키는 만드는 대상에 의도적으로 올리는 버전을 붙여 유도하세요. 키 설계는 AI 영상 API 멱등성 키에서 다룹니다.
job_not_completed는 항상 기다리면 되나요?
아닙니다. GET /v1/jobs/{id}/result는 돌려줄 결과가 없으므로 실패하거나 취소된 Job에도 409 job_not_completed로 응답합니다. 현재 코드에서는 그런 경우에도 이 오류가 retryable: true, next_action: poll_status로 표시되므로, 이 플래그만 보고 반복하지 마세요. GET /v1/jobs/{id}에서 Job 레코드를 읽고, 상태가 종료 상태가 되면 멈추세요. Format 실행은 다릅니다. run_not_completed는 실행이 아직 진행 중일 때만 돌아오고 현재 상태가 details.status에 담기므로, 이때는 기다리는 것이 맞습니다.
코드에서 409는 어떻게 처리하나요?
HTTP 상태로 먼저 분기하고, 그다음 error.code로 분기하세요. error.code는 switch 문에 쓸 수 있는 소문자 토큰이고, message는 사람이 읽는 용도이며 바뀔 수 있습니다. retryable은 같은 요청을 다시 보내서 성공할 수 있는지 알려 줍니다. TypeScript SDK는 409를 대신 다시 보내 주지 않습니다. SDK 클라이언트는 408, 429, 5xx를 재시도하고, 409는 code, retryable, details를 담은 SumeConflictError로 던집니다(실행 헬퍼는 대신 SumeRunRequestError를 던집니다). 작은 판단 함수 하나로 위의 표를 코드에 옮길 수 있습니다.
type NextStep = "resend" | "wait" | "check-job" | "fix";
function nextStepFor409(code: string): NextStep {
switch (code) {
case "idempotency_key_in_use":
return "resend"; // after about a second: same key, same body
case "run_not_completed":
case "previous_run_not_terminal":
case "run_not_terminal":
case "format_run_in_progress":
case "action_run_in_progress":
return "wait"; // poll until the run is terminal, then call again
case "job_not_completed":
return "check-job"; // read GET /v1/jobs/{id}: it may have failed
default:
return "fix"; // resending as is won't help: see the table
}
}
// const { error } = await res.json(); when res.status === 409
// nextStepFor409(error.code);출처
관련 글
개발자 카테고리의 다른 글
- 415 Unsupported Media Type 오류: 원인과 해결법
415 Unsupported Media Type 오류는 서버가 요청 본문의 형식을 거부했다는 뜻입니다. Content-Type 헤더를 고쳐 JSON은 application/json으로 보내세요.
- 일괄 전사 API: 여러 오디오 파일을 텍스트로 변환하기
API 일괄 전사는 파일마다 음성 인식 Job을 하나씩 보내는 루프입니다. 키는 파일 ID로 만들고, 결과는 웹훅이나 폴링으로 모읍니다. Sume에서 동작하는 방식을 설명합니다.
- AI 이미지 대량 생성 API: 스크립트로 수백 장 만들기
행마다 이미지 요청을 하나씩 보내되, 요청마다 고유한 Idempotency-Key와 async 모드를 쓰고 호출당 최대 네 장을 요청하세요. 속도는 요금제의 동시성이 정합니다.
- 여러 사람이 같은 API 키를 써도 되나요?
쓸 수는 있지만, 그러면 키의 요청 한도와 사용 기록, 폐기까지 함께 나누게 됩니다. 사람이나 서비스마다 키를 따로 주고, 그래도 공유되는 것이 무엇인지 알아 두세요.
작성자 Sume