조회수: 92

409 Conflict 원인과 해결

409 Conflict는 요청이 리소스의 현재 상태와 충돌해 거부된 것입니다. 중복 키·오래된 ETag·실제 경쟁 상태를 구분합니다. 무료 즉시 진단으로 바로 확인.

내 도메인에 이 문제가 있는지 지금 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.

Problem

요청이 409 Conflict로 돌아옵니다. 요청 자체는 멀쩡했습니다 — 유효한 JSON, 올바른 인증, 존재하는 라우트 — 그런데 서버가 그 작업을 완료하면 리소스의 현재 상태와 충돌하기 때문에 거부합니다. 아무것도 망가지지 않았습니다. 서버는 당신의 요청이 가정한 자리에 세계가 있지 않다고 알려주는 겁니다.

Symptoms

  • 같은 리소스에 GET은 되는데 POST·PUT·PATCH·DELETE가 409를 반환합니다.
  • 두 번째 동일 요청에서 발생합니다 — 첫 요청은 성공했고 재시도가 충돌합니다.
  • 저장이 “다른 사용자가 레코드를 수정했습니다” 또는 “버전 불일치”로 실패합니다.
  • git push가 non-fast-forward로 거부되거나, 컨테이너 레지스트리가 이미 있는 태그를 거부합니다 — 둘 다 내부적으로 409입니다.

What 409 Actually Means

RFC 9110(§15.5.10)은 409를 “대상 리소스의 현재 상태와의 충돌 때문에 완료할 수 없는” 요청으로 정의합니다. 이 문장의 모든 단어가 중요합니다. 요청은 이해됐습니다. 인증도 통과했습니다. 문법도 유효했습니다. 서버는 그저 이미 존재하는 것과 모순되지 않고서는 그 요청을 적용할 수 없을 뿐입니다.

이건 다른 코드가 안 맞을 때 사람들이 집어드는 코드이고, 바로 거기에 함정이 있습니다. 400 Bad Request는 요청이 잘못된 형식 — 파싱 불가, 깨진 JSON, 누락된 필수 필드 — 이라는 뜻입니다. 500은 서버 자체가 버그에 걸린 겁니다. 409는 둘 다 아닙니다: 요청은 올바른 형식이고 서버도 잘 돌고 있습니다. 문제는 상태입니다. 이 구분이 진단의 전부입니다. 당신을 코드나 페이로드가 아니라 데이터로 안내하니까요.

명세는 대부분이 건너뛰는 한 줄을 덧붙입니다: 409는 업데이트가 충돌할 때 “PUT 요청에 대한 응답으로” 예상되며, “서버는 사용자가 충돌의 출처를 인식하기에 충분한 정보를 담은 콘텐츠를 생성해야 한다(SHOULD)“고요. 좋은 409 본문은 어떤 필드가 충돌했는지 알려줍니다. 게으른 409는 그냥 “Conflict”라고만 하고 당신을 추측하게 남겨둡니다. API를 직접 만든다면 충돌한 리소스를 본문에 담으세요. 그렇지 않은 API를 소비하고 있다면, 그 빠진 정보가 지금 당신이 이 글을 읽는 이유입니다.

Top 3 Causes

  1. 유니크 제약의 중복 - 전형적인 경우. 이미 존재하는 이메일, 이미 쓰인 슬러그, 이미 사용한 멱등성 키로 사용자를 POST 생성합니다. DB의 유니크 인덱스가 insert를 거부하고 API가 이를 500이 아닌 409로 번역합니다. 고칠 곳은 서버가 아닙니다 — 리소스가 이미 존재하니, 클라이언트가 그걸 가져오거나 생성을 멈춰야 합니다.

  2. 낙관적 동시성의 오래된 쓰기 - 버전 3에서 레코드를 읽었는데, 편집하는 동안 다른 사람이 버전 4를 저장했고, 당신의 PUT은 여전히 버전 3을 주장합니다. 서버는 버전을 비교하고 더 새 데이터를 덮어쓰길 거부합니다. API가 ETag로 If-Match를 쓰면 여기서 412가, 본문에서 자체 버전 검사를 하면 409가 나옵니다. 어느 쪽이든 해결은 동일합니다: 다시 읽고, 병합하고, 현재 버전에 재제출.

  3. 막힌 상태 전이 또는 종속성 - 다른 행이 아직 참조하는 리소스를 삭제하려 하거나, 이미 배송된 주문을 취소하거나, 현재 위치에서 진입 불가능한 상태로 워크플로를 옮기려 합니다. 추상적으로는 유효하지만 지금은 불법인 작업입니다. 서버가 자기 불변식을 지키며 409로 답합니다. 이건 진짜 비즈니스 로직을 숨기고 있고, 해결은 전적으로 도메인에 달렸습니다.

Diagnose with DechoNet

  • HTTP 진단으로 그 엔드포인트가 깨끗한 요청에 반환하는 정확한 상태 줄과 헤더를 보세요. 409는 보통 특정 상태를 향한 특정 쓰기에 묶여 있으므로, 평범한 진단은 자주 200이나 405로 돌아옵니다 — 그리고 그 갈림이 핵심입니다. 라우트가 중립적 요청에 정상 응답한다면 409는 망가진 배포가 아니라 당신의 페이로드 대 서버의 현재 데이터에 있습니다. 진단 자체가 모든 것에 409를 반환한다면, 충돌은 당신의 요청 본문이 아니라 라우팅이나 프록시에 박혀 있습니다.

Resolution Checklist

  • 코드만이 아니라 응답 본문을 읽으세요. 예의 바른 409는 충돌한 필드나 리소스를 이름으로 알려줍니다. 그렇다면 거의 끝났습니다 — 그게 이미 존재하는 행이거나 움직인 버전입니다.
  • 세 가지 형태 중 어느 것인지 정하세요. 중복 생성, 오래된 업데이트, 불법 전이. 상태 코드에서는 똑같아 보이지만 완전히 다른 해결이 필요합니다.
  • 중복 생성이면 재시도를 멈추고 대신 기존 리소스를 가져오세요. 클라이언트를 통제한다면 멱등성 키를 추가해, 재전송된 POST가 409 대신 원래 결과를 돌려주게 하세요.
  • 오래된 업데이트면 리소스를 다시 GET하고, 현재 버전/ETag를 취하고, 변경을 그 위에 병합하고, 재제출하세요. 같은 오래된 쓰기를 절대 반복하지 마세요 — 영원히 409입니다.
  • 막힌 전이면 서버가 지키는 비즈니스 규칙을 확인하세요. 종속 행을 먼저 삭제하거나, 합법적 중간 상태를 거쳐 가세요. 여기서 409는 제 일을 하고 있습니다.
  • 400이나 500이 변장한 게 아닌지 확인하세요. 페이로드가 정말 잘못된 형식이면 400이어야 하고, 서버가 처리 안 된 예외를 던졌으면 500이어야 합니다. 일부 API는 오표기합니다 — 정상으로 알려진 요청에 HTTP 진단을 돌리면 엔드포인트가 아예 건강한지 알 수 있습니다.

When to Escalate

  • 멱등이어야 할 POST가 정당한 재시도마다 409를 반환한다면 API 소유자에게 에스컬레이션하세요 — 불안정한 네트워크의 모바일 클라이언트가 유실된 ACK 때문에 벌받지 않도록 멱등성 키 경로가 필요할 겁니다.
  • 배포 직후 409가 치솟으면, 기존 중복이 있는 컬럼에 유니크 제약을 추가한 마이그레이션이나, 이제 정상 트래픽에 발동하는 동시성 검사를 의심하세요. 이건 데이터 문제이고, 마이그레이션을 실행한 쪽의 몫입니다.

관련 도구

관련 가이드

가이드 공유

[Ad] Guide Detail Inline
← 전체 가이드 보기