Skip to content

Missing ProcessingExceptionHandler causes fatal crash in Kafka Streams internal processing #515

@AnkurSinhaaa

Description

@AnkurSinhaaa

Description

While using a Kafka topic as a GlobalKTable, the application crashes with a NullPointerException when a processing error occurs.
This happens because ProcessingExceptionHandler is not configured in kstreamplify, and Kafka Streams attempts to invoke it as part of its internal error handling mechanism.

Observed Behavior

When a Schema Registry error occurs during GlobalKTable updates, the application fails with:

SerializationException: Error registering Avro schema
Caused by: RestClientException: Schema not found (40403)

This is followed by a fatal error:

java.lang.NullPointerException:
Cannot invoke "org.apache.kafka.streams.errors.ProcessingExceptionHandler.handle(...)"
because "this.processingExceptionHandler" is null

And eventually:

Fatal user code error in processing error callback
→ Kafka Streams shuts down

Context (GlobalKTable specific)

This issue was encountered when:

  • A Kafka topic was directly configured as a GlobalKTable
  • The topology uses Avro with Schema Registry
  • A schema was missing or not registered

The failure happens inside:

  • GlobalStreamThread
  • GlobalStateUpdateTask
  • KTableSourceProcessor

These execution paths are not covered by TopologyExceptionHandler.catchErrors


Why this happens

  • Kafka Streams internally relies on ProcessingExceptionHandler
  • kstreamplify does not configure this handler
  • When an exception occurs outside TopologyExceptionHandler.catchErrors, Kafka tries to call:
processingExceptionHandler.handle(...)

Since it is null, Kafka Streams throws a NullPointerException, masking the original exception.


Important Note

This issue still occurs because TopologyExceptionHandler.catchErrors(...) only wraps user-defined topology logic where explicitly applied, and does not cover exceptions occurring in Kafka Streams internal processing, such as:

  • GlobalKTable updates (GlobalStreamThread)
  • State store operations triggered internally (e.g. materialization)
  • Internal processing nodes (e.g. ProcessorNode)

As a result, these exceptions rely on ProcessingExceptionHandler, which is not configured by kstreamplify.


Impact

  • Application crashes instead of handling errors gracefully

  • Original exception (Schema Registry error) is masked

  • No DLQ or recovery mechanism is triggered

  • Particularly affects:

    • GlobalKTable
    • State store updates
    • Schema Registry integration

Workaround

Manually configure a ProcessingExceptionHandler:

@Slf4j
public class DebugProcessingHandler implements ProcessingExceptionHandler {

    @Override
    public ProcessingHandlerResponse handle(
            ErrorHandlerContext context,
            Record<?, ?> record,
            Exception exception) {

        log.error("Processing error", exception);
        return ProcessingHandlerResponse.CONTINUE;
    }
}

Suggested Improvement

  1. Provide a default ProcessingExceptionHandler in kstreamplify

  2. Ensure it is applied globally, including GlobalStreamThread

  3. Optionally implement:

    • DlqProcessingExceptionHandler (similar to our deserialization DLQ handler)
  4. Clarify documentation:

    • TopologyExceptionHandler.catchErrors does not cover all processing paths

Expected Behavior

  • Processing errors should not result in NullPointerException

  • Application should:

    • continue processing, or
    • route failed records to DLQ

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementThis issue or pull request improves a feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions