Kafka Streams Deserialization Handler
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
In Kafka Streams, deserialization happens before your topology logic sees a record. If deserialization fails, the application must decide whether to stop or skip the bad record. That decision is controlled by the deserialization exception handler configuration.
Why This Handler Matters
Kafka Streams consumes bytes from Kafka and converts them into keys and values using configured serdes. If the incoming bytes do not match the expected format, deserialization throws an error before the record enters your stream logic.
Without a clear policy, a single malformed record can halt an otherwise healthy application. In other workloads, silently skipping bad data would be worse than stopping. The right handler depends on your error budget and data-integrity requirements.
Built-In Handler Options
Kafka Streams provides two common built-in policies:
- '
LogAndFailExceptionHandler' - '
LogAndContinueExceptionHandler'
LogAndFailExceptionHandler is conservative. It logs the problem and stops processing. This is usually the right choice when data loss is unacceptable.
LogAndContinueExceptionHandler logs the problem and skips the record. This is useful when the stream should stay alive even if some events are malformed.
Configure a Built-In Handler
You configure the handler in the Streams application properties.
That one property changes what the application does when a record cannot be deserialized.
Implement a Custom Handler
If the built-in choices are too blunt, implement DeserializationExceptionHandler yourself.
Then register it just like a built-in handler:
What a Custom Handler Should Usually Do
A custom handler is a good place to add structured logging, metrics, or alert-friendly context. For example, you might record the topic, partition, offset, and exception type so operators can find the exact bad event.
What a custom handler should not do is try to repair arbitrary broken payloads blindly. If records are malformed often enough to need complex recovery, the schema and producer contracts usually need attention upstream.
Choosing Between Fail and Continue
Use fail-fast behavior when:
- every record matters
- bad input indicates a serious upstream bug
- silent loss would be unacceptable
Use continue behavior when:
- occasional bad records are expected
- downstream consumers can tolerate missing malformed events
- availability matters more than strict completeness
The key is to choose intentionally. "Continue" is not free. It means dropping data.
Do Not Confuse This With Processing Exceptions
Deserialization handlers deal only with failures while converting bytes into objects. They do not handle exceptions thrown later by your topology code, processors, or downstream services. Those failure modes need separate handling strategies.
That distinction matters operationally because a stream can deserialize successfully and still fail later for completely different reasons.
Common Pitfalls
The biggest mistake is using LogAndContinueExceptionHandler without good metrics or logging. The application keeps running, but bad data disappears unless you can measure it.
Another issue is choosing fail-fast behavior in a noisy environment without understanding the restart impact. A single recurring malformed record can repeatedly crash the app.
Developers also sometimes assume the deserialization handler covers all stream exceptions. It only covers serde failures before records enter the topology.
Finally, if many records are failing deserialization, do not hide the issue forever with a continue policy. That is usually a producer, schema, or compatibility problem that deserves a real fix.
Summary
- Kafka Streams deserialization handlers decide what happens when incoming bytes cannot be converted into objects.
- Built-in options include fail-fast and log-and-continue behavior.
- A custom handler can add logging, metrics, and application-specific policy.
- Skipping bad records improves availability but can introduce silent data loss.
- Deserialization handling is only one part of stream error handling, not the whole story.
Related reading
- Kafka Streams does not increment offset by 1 when producing to topic
- Kafka Streams dynamic routing (ProducerInterceptor might be a solution?)
- Kafka Streams error - Offset commit failed on partition, request timed out
- Kafka streams error SerializationException Size of data received by LongDeserializer is not 8
- Kafka Streams Failed to flush state store caused by java.lang.ClassCastException cannot case key to value
- Kafka Streams How to ensure offset is committed after processing is completed
- Kafka Streams how to get the kafka headers
- Kafka Streams how to write to a topic?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.