Kafka clients must handle various failure scenarios including network errors, broker failures, and timeout conditions. This guide covers retry mechanisms, idempotent producers, transactional semantics, and error recovery strategies.
Retriable, non-retriable, and fatal Kafka client error categories Retriable, non-retriable, and fatal Kafka client error categories Failure Types Retriable Errors Non-Retriable Errors Fatal Errors NOT_LEADER_OR_FOLLOWER REQUEST_TIMED_OUT NETWORK_EXCEPTION COORDINATOR_LOAD_IN_PROGRESS TOPIC_AUTHORIZATION_FAILED RECORD_TOO_LARGE INVALID_REQUIRED_ACKS UNKNOWN_TOPIC_OR_PARTITION OUT_OF_ORDER_SEQUENCE_NUMBER INVALID_PRODUCER_EPOCH TRANSACTIONAL_ID_AUTHORIZATION_FAILED
Error Code Name Cause Client Action 3 UNKNOWN_TOPIC_OR_PARTITIONTopic missing or metadata stale Refresh metadata; retry only if topic is expected to exist 5 LEADER_NOT_AVAILABLEElection in progress Wait and retry 6 NOT_LEADER_OR_FOLLOWERStale metadata Refresh metadata, retry 7 REQUEST_TIMED_OUTBroker too slow Retry 15 NETWORK_EXCEPTIONConnection failed Reconnect, retry
Error Code Name Cause Client Action 13 RECORD_TOO_LARGEMessage > max.message.bytes Reduce message size 17 INVALID_REQUIRED_ACKSInvalid acks setting Fix configuration 29 TOPIC_AUTHORIZATION_FAILEDNo permission Check ACLs 74 INVALID_TXN_STATETransaction state error Abort transaction
Producer request retry decision flow Producer request retry decision flow Send request Success? yes no Complete with result Retriable error? yes no Retries exhausted? yes no Throw exception Increment retry count Apply backoff Refresh metadata (if needed) Retry request Throw exception
retries =2147483647 # Max int (default, Kafka 2.1+)
# Backoff between retries
retry.backoff.ms =100 # 100ms (default)
# Maximum retry backoff (Kafka 2.6+)
retry.backoff.max.ms =1000 # 1 second
delivery.timeout.ms =120000 # 2 minutes (default)
Exponential Backoff with Jitter Exponential Backoff with Jitter Retry Attempts Attempt 1 Backoff 100ms Attempt 2 Backoff 200ms Attempt 3 Backoff 400ms Attempt 4 0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500
Timeout relationship inside delivery.timeout.ms Timeout relationship inside delivery.timeout.ms delivery.timeout.ms (total) linger.ms request.timeout.ms retry time delivery.timeout.ms >= linger.ms + request.timeout.ms Retry attempts occur within this window
# Total delivery time budget
delivery.timeout.ms =120000 # 2 minutes
# Time for batch accumulation
# Time for single request
request.timeout.ms =30000 # 30 seconds
# Retries happen within delivery.timeout.ms
Idempotent producers enable exactly-once semantics within a single partition, preventing duplicate messages from retries.
Idempotent producer deduplicating a retried produce request Producer Broker Producer (PID=1) Producer (PID=1) Broker Broker Produce(seq=0) Ack Produce(seq=1) Network timeout (ack lost) Produce(seq=1) [retry] Broker detects duplicate: PID=1, seq=1 already seen Returns success (idempotent) Ack (no duplicate written) Produce(seq=2) Ack
# Required settings (set automatically when idempotence enabled)
max.in.flight.requests.per.connection =5 # or less
Component Description Producer ID (PID) Unique ID assigned by broker Epoch Increments on producer restart Sequence Number Per-partition, monotonically increasing
Idempotent producer state of producer ID, epoch, and per-partition sequence numbers Idempotent producer state of producer ID, epoch, and per-partition sequence numbers Idempotent Producer State Sequence Numbers PID: 12345 Epoch: 0 P0: 42 P1: 17 P2: 103 Broker tracks highest seq per PID/partition Rejects out-of-order or duplicate sequences
Transactions enable exactly-once semantics across multiple partitions and consumer groups.
Transactional producer flow from InitProducerId to commit Producer Transaction Broker Producer Producer Transaction Coordinator Transaction Coordinator Broker Broker Initialize InitProducerId (transactional.id) PID, Epoch Transaction BeginTransaction AddPartitionsToTxn Produce(P0, TXN) Ack Produce(P1, TXN) Ack Commit EndTxn(COMMIT) WriteTxnMarker(COMMIT) Ack Success
# Required for transactions
transactional.id =my-transactional-producer
# Automatically enabled with transactional.id
transaction.timeout.ms =60000 # 1 minute
producer . initTransactions () ;
producer . beginTransaction () ;
producer . send ( new ProducerRecord <>( " orders " , key, value) ) ;
producer . send ( new ProducerRecord <>( " inventory " , key, update) ) ;
// Send consumer offsets as part of transaction
producer . sendOffsetsToTransaction ( offsets, consumerGroupId ) ;
producer . commitTransaction () ;
} catch ( ProducerFencedException | OutOfOrderSequenceException e ) {
// Fatal - close producer
} catch ( KafkaException e ) {
producer . abortTransaction () ;
Setting Consumer Behavior isolation.level=read_uncommittedSees all messages (including uncommitted) isolation.level=read_committedOnly sees committed messages
Consumer offset commit with auto-commit and manual commit Consumer Coordinator Consumer Consumer Coordinator Coordinator poll() Records (offset 100-150) Process records alt [Auto-commit] enable.auto.commit=true Commit(151) (background) [Manual commit] commitSync(151) On failure before commit: Records 100-150 reprocessed (at-least-once)
consumer . subscribe ( topics, new ConsumerRebalanceListener () {
public void onPartitionsRevoked ( Collection < TopicPartition > partitions ) {
// Commit pending offsets before losing partitions
consumer . commitSync ( currentOffsets ) ;
} catch ( CommitFailedException e ) {
log . warn ( " Commit failed on revoke " , e ) ;
public void onPartitionsAssigned ( Collection < TopicPartition > partitions ) {
// Initialize state for new partitions
for ( TopicPartition partition : partitions) {
initializePartitionState ( partition ) ;
Scenario Impact Mitigation Consumer crash Uncommitted messages reprocessed Idempotent processing Long processing Rebalance triggered Increase max.poll.interval.ms Commit failure Duplicate processing Retry commit Deserialization error Poison pill Dead letter queue
Client connection state transitions during reconnection Client connection state transitions during reconnection Connected Disconnected Reconnecting Exponential backoff: reconnect.backoff.ms up to reconnect.backoff.max.ms initial connect connection lost backoff expired failure success
# Initial reconnection backoff
# Maximum reconnection backoff
reconnect.backoff.max.ms =1000
socket.connection.setup.timeout.ms =10000
socket.connection.setup.timeout.max.ms =30000
producer . send ( record, (metadata, exception) -> {
log . info ( " Sent to partition {} offset {} " ,
metadata . partition () , metadata . offset ()) ;
} else if (exception instanceof RetriableException) {
// Retriable - will be retried automatically
log . warn ( " Retriable error, will retry: {} " , exception . getMessage ()) ;
// Non-retriable - handle or dead-letter
log . error ( " Non-retriable error: {} " , exception . getMessage ()) ;
sendToDeadLetter ( record, exception ) ;
ConsumerRecords < String , String > records = consumer . poll ( Duration . ofMillis ( 100 )) ;
for ( ConsumerRecord < String , String > record : records) {
} catch ( ProcessingException e ) {
// Send to dead letter queue
sendToDeadLetter ( record, e ) ;
} catch ( WakeupException e ) {
} catch ( CommitFailedException e ) {
// Rebalance during commit - records will be redelivered
log . warn ( " Commit failed due to rebalance " , e ) ;
Dead letter queue topology for failed record processing Dead letter queue topology for failed record processing Main Consumer DLQ Consumer poll() process() Retry/Alert Main Topic Dead Letter Topic on failure
Configuration Guarantee Duplicates Loss acks=0Fire and forget Possible Possible acks=1Leader ack Possible Possible acks=allFull ISR ack Possible No* acks=all + idempotenceExactly-once (partition) No No Transactions Exactly-once (cross-partition) No No
*With min.insync.replicas configured
Pattern Guarantee Duplicates Loss Auto-commit Not guaranteed (can be at-most-once) Possible Possible Commit before process At-most-once No Possible Commit after process At-least-once Possible No Transactional Exactly-once No No
Metric Description Alert Condition record-error-rateErrors per second > 0 sustained record-retry-rateRetries per second Unusually high record-send-rateSuccessful sends Drop from baseline request-latency-avgRequest latency > threshold
Metric Description Alert Condition failed-rebalance-rateFailed rebalances > 0 last-poll-seconds-agoTime since poll > max.poll.interval.ms commit-latency-avgCommit latency > threshold records-lagConsumer lag Increasing
Practice Rationale Enable idempotence Prevent duplicates from retries Set reasonable delivery.timeout.ms Bound total retry time Use callbacks for error handling Non-blocking error handling Implement dead letter queue Handle persistent failures
Practice Rationale Commit after processing At-least-once guarantee Implement idempotent processing Handle duplicates Use read_committed with transactions See only committed data Handle rebalance callbacks Clean state management
Feature Minimum Version Basic retries 0.8.0 Idempotent producer 0.11.0 Transactions 0.11.0 delivery.timeout.ms2.1.0 Cooperative rebalancing 2.4.0