<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Error-Handling on Devops Monk</title><link>https://devops-monk.com/tags/error-handling/</link><description>Recent content in Error-Handling on Devops Monk</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 04 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://devops-monk.com/tags/error-handling/index.xml" rel="self" type="application/rss+xml"/><item><title>Dead Letter Topics: Routing Failed Messages with DeadLetterPublishingRecoverer</title><link>https://devops-monk.com/tutorials/spring-kafka/dead-letter-topics/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://devops-monk.com/tutorials/spring-kafka/dead-letter-topics/</guid><description>What Is a Dead Letter Topic? When a record fails processing and retries are exhausted, you have two options: skip it (losing the data) or park it somewhere for inspection and reprocessing. A dead-letter topic (DLT) is that parking lot — a Kafka topic that holds records that could not be processed, enriched with error metadata headers.
flowchart LR subgraph Main["orders topic"] R1["record: offset 42\n(bad data)"] end subgraph DLT["orders.DLT topic"] R2["</description></item><item><title>Error Handling Basics: DefaultErrorHandler and CommonErrorHandler</title><link>https://devops-monk.com/tutorials/spring-kafka/error-handling-basics/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://devops-monk.com/tutorials/spring-kafka/error-handling-basics/</guid><description>What Happens When a Listener Throws? Without an error handler, an uncaught exception from @KafkaListener causes the container to log the error and retry the same record on the next poll — indefinitely. One bad record can block an entire partition forever.
DefaultErrorHandler fixes this: it retries a configurable number of times with backoff, then calls a ConsumerRecordRecoverer (e.g. send to a dead-letter topic) and moves on.
DefaultErrorHandler — The Modern API Spring Kafka 2.</description></item><item><title>Handling Deserialization Errors Gracefully</title><link>https://devops-monk.com/tutorials/spring-kafka/deserialization-errors/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://devops-monk.com/tutorials/spring-kafka/deserialization-errors/</guid><description>The Problem: Poison Pills at Deserialization Time A malformed byte sequence — truncated JSON, wrong Avro schema, corrupt payload — throws an exception during deserialization, before the listener method is called. Without special handling, this record blocks the partition indefinitely: the consumer fetches it, fails to deserialize, and fetches it again on the next poll.
sequenceDiagram participant Broker participant Container participant Deserializer loop forever without ErrorHandlingDeserializer Container->>Broker: poll() Broker-->>Container: [good-record, CORRUPT-RECORD, good-record] Container->>Deserializer: deserialize(CORRUPT-RECORD) Deserializer-->>Container: JsonProcessingException 💥 Note over Container: Partition blocked — same record on every poll end ErrorHandlingDeserializer solves this by catching the deserialization exception and wrapping it in a DeserializationException that the listener container can route to the error handler.</description></item><item><title>Retryable vs Non-Retryable Exceptions: Custom Exception Classification</title><link>https://devops-monk.com/tutorials/spring-kafka/retryable-exceptions/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://devops-monk.com/tutorials/spring-kafka/retryable-exceptions/</guid><description>Transient vs Permanent Failures Not every exception is worth retrying. Retrying a NullPointerException or a schema validation error wastes time and delays other records. Retrying a database timeout or a downstream HTTP 503 is exactly right — the error is temporary and will likely resolve.
flowchart TD Ex["Exception in listener"] Q{"Transient?\n(DB timeout, HTTP 503,\nnetwork blip)"} Q -->|Yes| Retry["Retry with BackOff"] Q -->|No| Skip["Call recoverer immediately\n(no retries wasted)"] Retry -->|"still failing after\nmax retries"</description></item></channel></rss>