Files
llm-wiki/raw/official-docs/spring-kafka-error-handling-deserializer-poison-record.md

11 KiB
Raw Permalink Blame History

title, source_type, url, archive_url, related_branches, related_projects, tags, created
title source_type url archive_url related_branches related_projects tags created
official-doc / Spring for Apache Kafka — ErrorHandlingDeserializer (Poison Record Handling) official-doc https://docs.spring.io/spring-kafka/reference/kafka/serdes.html
feature-kafka-consumer-inbox-contract
ca-skeleton
official-doc
ca-skeleton
messaging
kafka
dead-letter-queue
2026-07-28

official-doc / Spring for Apache Kafka — ErrorHandlingDeserializer (Poison Record Handling)

Layer: raw/ — 외부 자료(공식 문서)의 원문 발췌·출처 기록. 검증된 요약은 /ingestwiki/concepts/에 별도 작성. 원본은 raw에 영구 보관.

Parent / 활용 branch

Branch 이 자료가 정당화하는 결정
raw/branch-notes/feature-kafka-consumer-inbox-contract ca-skeleton consumer 가 역직렬화 실패(poison message)를 "리스너 호출 이전 단계에서 감지해 error handler/DLT 경로로 회수"하는 방식을 채택하는 근거 — ErrorHandlingDeserializer 가 실패 시 null 값 + DeserializationException 헤더(원인 + raw bytes)를 실어 보내고, 컨테이너가 리스너 대신 error handler 를 호출한다는 공식 메커니즘

출처

  • 원본 URL: https://docs.spring.io/spring-kafka/reference/kafka/serdes.html
  • 아카이브 URL: (미제공)
  • 저자 / 조직: Spring team (Broadcom / VMware Tanzu — Spring for Apache Kafka reference)
  • 문서 버전: Spring for Apache Kafka reference 4.1.0 (페이지 상단 breadcrumb "Spring for Apache Kafka 4.1.0" 및 페이지 메타 content="4.1.0" 확인). ErrorHandlingDeserializer 절 본문 자체에 버전 도입 표기는 없으나, Validator 추가 기능은 "Starting with version 3.1"로 명시됨
  • 발행일: 페이지 자체 발행일 표기 없음 (기능별 "Starting with version N.N" 문구만 본문에 존재)
  • 마지막 확인일: 2026-07-28

왜 저장했는지

ca-skeleton kafka consumer inbox 브랜치(feature-kafka-consumer-inbox-contract)의 "rebalance·max.poll 처리, poison/역직렬화 실패 분류" 범위에서, poison message 를 리스너 도달 이전 단계(deserializer 레벨)에서 걸러 error handler/DLT 로 회수하는 설계를 공식 메커니즘으로 정당화하기 위함. ErrorHandlingDeserializer 가 무엇을 반환하고 컨테이너가 어떻게 반응하는지의 원문 계약을 근거로 남긴다.

핵심 인용

원문 그대로. 이 페이지는 단일 섹션("Using ErrorHandlingDeserializer")이며 하위 번호 섹션이 없어, 위치는 fetched text(/tmp/source-fetch-20260728-171842.txt)의 line 번호로 표기한다 (self-grep 참조).

[Using ErrorHandlingDeserializer] "When a deserializer fails to deserialize a message, Spring has no way to handle the problem, because it occurs before the poll() returns." (line 578)

[Using ErrorHandlingDeserializer] "If the delegate fails to deserialize the record content, the ErrorHandlingDeserializer returns a null value and a DeserializationException in a header that contains the cause and the raw bytes." (line 581)

[Using ErrorHandlingDeserializer] "When you use a record-level MessageListener, if the ConsumerRecord contains a DeserializationException header for either the key or value, the container's ErrorHandler is called with the failed ConsumerRecord." "The record is not passed to the listener." (line 582583)

[Using ErrorHandlingDeserializer] "You can use the DefaultKafkaConsumerFactory constructor that takes key and value Deserializer objects and wire in appropriate ErrorHandlingDeserializer instances that you have configured with the proper delegates. Alternatively, you can use consumer configuration properties (which are used by the ErrorHandlingDeserializer) to instantiate the delegates. The property names are ErrorHandlingDeserializer.KEY_DESERIALIZER_CLASS and ErrorHandlingDeserializer.VALUE_DESERIALIZER_CLASS." (line 593595)

Claims Extracted

Claim ID Claim Evidence quote Strength Applies to Does not prove
SPRK-EHD-C1 표준 Kafka Deserializerpoll() 반환 이전에 발생하는 역직렬화 실패를 리스너 레벨에서 처리할 방법이 없고, 이 문제를 해결하기 위해 ErrorHandlingDeserializer 가 도입되었다 "When a deserializer fails to deserialize a message, Spring has no way to handle the problem, because it occurs before the poll() returns." + "To solve this problem, the ErrorHandlingDeserializer has been introduced." official-vendor-doc poison message 문제의 근본 원인(왜 일반 deserializer 로는 리스너 레벨 에러 처리가 불가능한지)과 ErrorHandlingDeserializer 도입 동기 ErrorHandlingDeserializer 외 다른 해결책(예: try-catch 를 감싼 custom deserializer)의 존재·우열 비교
SPRK-EHD-C2 위임(delegate) deserializer 가 레코드 내용 역직렬화에 실패하면, ErrorHandlingDeserializernull 값과, cause + raw bytes 를 담은 DeserializationException 헤더를 반환한다 "If the delegate fails to deserialize the record content, the ErrorHandlingDeserializer returns a null value and a DeserializationException in a header that contains the cause and the raw bytes." official-vendor-doc ErrorHandlingDeserializer 가 key 또는 value deserializer 로 설정된 경우의 실패 시 반환 값·헤더 계약 batch listener 컨테이너에서 이 헤더가 동일하게 자동 노출/처리되는지 (문서 후반 별도 절 "Batch Listener Error Handling" 에서 수동 검사 코드로 별도 처리됨 — 자동 아님)
SPRK-EHD-C3 record-level MessageListener 사용 시, ConsumerRecordDeserializationException 헤더(key 또는 value)가 있으면 컨테이너의 ErrorHandler 가 실패한 ConsumerRecord 와 함께 호출되고, 그 레코드는 리스너로 전달되지 않는다 "When you use a record-level MessageListener, if the ConsumerRecord contains a DeserializationException header for either the key or value, the container's ErrorHandler is called with the failed ConsumerRecord." + "The record is not passed to the listener." official-vendor-doc record-level(단일 레코드) @KafkaListener 의 poison record 라우팅 경로 — 리스너 도달 이전에 error handler 로 우회된다는 계약. 본 branch 의 "리스너 호출 이전 단계에서 감지해 error handler/DLT 경로로 회수" 결정의 직접 근거 DLT 로의 실제 라우팅(예: DefaultErrorHandler + DeadLetterPublishingRecoverer 조합)은 이 페이지에 명시되지 않음 — 별도 자료("Handling Exceptions" 페이지) 확인 필요. batch listener 의 라우팅 경로도 별도(문서 후반 절 참조)
SPRK-EHD-C4 위임 deserializer 는 DefaultKafkaConsumerFactory 생성자로 직접 wiring 하거나, ErrorHandlingDeserializer.KEY_DESERIALIZER_CLASS / ErrorHandlingDeserializer.VALUE_DESERIALIZER_CLASS 컨슈머 설정 프로퍼티로 지정할 수 있다 "You can use the DefaultKafkaConsumerFactory constructor that takes key and value Deserializer objects and wire in appropriate ErrorHandlingDeserializer instances that you have configured with the proper delegates. Alternatively, you can use consumer configuration properties (which are used by the ErrorHandlingDeserializer) to instantiate the delegates. The property names are ErrorHandlingDeserializer.KEY_DESERIALIZER_CLASS and ErrorHandlingDeserializer.VALUE_DESERIALIZER_CLASS." official-vendor-doc ErrorHandlingDeserializer 에 실제 위임 deserializer(예: JsonDeserializer)를 지정하는 두 가지 설정 방법(생성자 vs 프로퍼티) Spring Boot spring.kafka.* 프로퍼티에서 이 설정이 어떤 정확한 키로 자동 매핑되는지(이 페이지는 raw ConsumerConfig 프로퍼티 예시만 제공)

Strength 참고

모든 claim 은 official-vendor-doc (Spring 공식 reference — RFC/IETF 표준이 아니므로 official-standard 로 격상하지 않음)이다.

Usage Boundaries

  • 이 자료가 직접 증명하는 것:
    • SPRK-EHD-C1: 일반 deserializer 로는 poll() 이전 실패를 리스너 레벨에서 처리 불가능하다는 문제와 ErrorHandlingDeserializer 도입 동기
    • SPRK-EHD-C2: 위임 deserializer 실패 시 null + DeserializationException 헤더 반환 계약
    • SPRK-EHD-C3: record-level 리스너에서 실패 레코드가 리스너 대신 컨테이너 ErrorHandler 로 라우팅된다는 계약 — 리스너 호출 이전 감지 결정의 직접 근거
    • SPRK-EHD-C4: delegate deserializer 를 지정하는 두 가지 설정 방법(생성자 wiring / 컨슈머 프로퍼티)
  • 이 자료가 증명하지 않는 것:
    • DLT(Dead Letter Topic)로의 실제 라우팅 구현(DefaultErrorHandler + DeadLetterPublishingRecoverer 조합의 상세 동작) — 이 페이지에는 등장하지 않음
    • batch listener 컨테이너에서의 동일 계약(별도 수동 헤더 검사 코드 필요 — 문서 후반 "Batch Listener Error Handling" 절에서 별도로 다룸, 본 인용 범위 밖)
    • 이 메커니즘이 ca-skeleton 의 handler/schema/version allowlist 설계와 어떻게 결합되어야 하는지
    • retry topic 또는 지연 재시도 정책과의 상호작용(이 페이지 미언급 — Non-Blocking Retries 페이지 별도 확인 필요)
  • 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
    • DLT 라우팅과 감사된 replay 를 위한 실제 error handler 구성(DefaultErrorHandler/DeadLetterPublishingRecoverer)은 "Handling Exceptions" 공식 페이지를 별도 wiki-source-summarizer dispatch 로 조사한 뒤 확정
    • batch listener 를 채택할 경우 poison record 검출 코드를 리스너 본문에 직접 작성해야 한다는 것(자동 아님)을 /branch-spec 결정에 반영할지 여부

메모

나중에 wiki로 옮길 때 참고할 짧은 메모. 검증되지 않은 내 추론은 여기에 두지 말 것.

  • 사용자가 최초 요청한 인용 문구는 backtick(code font) 표기를 포함했으나, 실제 원문 HTML 은 <code> 태그로 감싼 것이지 별도 마크다운 backtick 문자가 존재하지 않는다. 본 raw 문서의 verbatim 인용은 backtick 을 제거한 원문 텍스트 그대로이며, 의미는 사용자 요청과 100% 일치함 (self-grep 확인 완료).
  • WebFetch 도구의 1차 결과는 AI 요약 모델을 거쳐 문장이 재구성되어("delegates to a real deserializer and returns...") 있었다 — verbatim 요구사항에 부적합해 폐기하고, curl 로 원본 HTML 을 직접 받아 태그만 제거한 텍스트로 self-grep 을 재실행했다.
  • 추가로 봐야 할 동일 출처 페이지: "Handling Exceptions" (DLT/DefaultErrorHandler/DeadLetterPublishingRecoverer 실제 구성) — 별도 URL, 별도 dispatch 필요.

관련

  • 같은 주제 다른 official-doc: [[raw/official-docs/spring-kafka-listener-container-pause-resume-backpressure]], [[raw/official-docs/spring-kafka-non-blocking-retry-topic-ordering-loss]]
  • 이 자료를 인용한 wiki 요약: [[wiki/concepts/...]] (생성 시)