Skip to content
Kafka Is Fun

Production Patterns · Intermediate · Topic 1 of 5

DefaultErrorHandler with Dead Letter Topic

DefaultErrorHandler is the container's default error handler. It retries a failed record by seeking back to it, following a BackOff, and when retries are exhausted it calls a recoverer. The default is FixedBackOff(0L, 9) and logging; DeadLetterPublishingRecoverer publishes the failed record to <topic>-dlt (the same partition, by default).

KafkaConsumerConfig.javajava
@Configuration
@Slf4j
public class KafkaConsumerConfig {

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, Object> kafkaListenerContainerFactory(
        ConsumerFactory<String, Object> consumerFactory,
        KafkaTemplate<String, Object> kafkaTemplate
    ) {
        var factory = new ConcurrentKafkaListenerContainerFactory<String, Object>();
        factory.setConsumerFactory(consumerFactory);
        factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);

        // DeadLetterPublishingRecoverer sends failed records to {topic}-dlt, same partition
        var recoverer = new DeadLetterPublishingRecoverer(kafkaTemplate,
            (record, ex) -> new TopicPartition(record.topic() + "-dlt", record.partition()));

        // 3 retries with exponential back off (1 s, 2 s, 4 s, capped at 10 s), then the recoverer
        var backOff = new ExponentialBackOffWithMaxRetries(3);
        backOff.setInitialInterval(1_000L);
        backOff.setMultiplier(2.0);
        backOff.setMaxInterval(10_000L);

        var errorHandler = new DefaultErrorHandler(recoverer, backOff);

        // Add exception types that must not be retried: they go straight to the recoverer
        errorHandler.addNotRetryableExceptions(IllegalArgumentException.class);

        // With MANUAL_IMMEDIATE, commit the offset of a record the recoverer handled
        errorHandler.setCommitRecovered(true);

        factory.setCommonErrorHandler(errorHandler);
        factory.setConcurrency(3);
        return factory;
    }
}

Sources

Checked against Spring for Apache Kafka 4.1.1, Spring Boot 4.1.1 and Kafka 4.2 documentation on 11 October 2026. Draft: not yet reviewed by a Kafka specialist, and releases move on, so confirm against the current documentation before you act on it.