apache/kafka · error · org.apache.kafka.common.errors.TimeoutException
Operation timed out before completion
Error message
Operation timed out before completion
What it means
Thrown by AsyncKafkaConsumer.processBackgroundEvents as a TimeoutException when the overall timer expires before the enqueued background event completes its CompletableFuture. The async consumer drives work on a background network thread and the application thread polls for completion; if the broker, coordinator, or callback chain does not finish within the operation's deadline (default.api.timeout.ms or the request-specific timer), this generic timeout fires. The message is intentionally generic because the same loop backs poll(), commitSync, position(), unsubscribe and other blocking calls.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java:2479
// If the event is done (either successfully or otherwise), go ahead and attempt to return
// without waiting. We use the ConsumerUtils.getResult() method here to handle the conversion
// of the exception types.
return ConsumerUtils.getResult(future);
} else if (!hadEvents) {
// If the above processing yielded no events, then let's sit tight for a bit to allow the
// background thread to either finish the task, or populate the background event
// queue with things to process in our next loop.
Timer pollInterval = time.timer(100L);
return ConsumerUtils.getResult(future, pollInterval);
}
} catch (TimeoutException swallow) {
// Ignore this as we will retry the event until the timeout expires.
} finally {
timer.update();
}
} while (timer.notExpired());
throw new TimeoutException("Operation timed out before completion");
}
static ConsumerRebalanceListenerCallbackCompletedEvent invokeRebalanceCallbacks(ConsumerRebalanceListenerInvoker rebalanceListenerInvoker,
ConsumerRebalanceListenerMethodName methodName,
SortedSet<TopicPartition> partitions,
CompletableFuture<Void> future) {
Exception e;
try {
switch (methodName) {
case ON_PARTITIONS_REVOKED:
e = rebalanceListenerInvoker.invokePartitionsRevoked(partitions);
break;
case ON_PARTITIONS_ASSIGNED:
e = rebalanceListenerInvoker.invokePartitionsAssigned(partitions);
break;
View on GitHub (pinned to c31c9215e1)
Solutions
- Increase default.api.timeout.ms and/or request.timeout.ms to values that match your cluster's observed latency, and verify the broker is healthy.
- Inspect the consumer logs for the underlying cause: TimeoutException here is a wrapper; look for the preceding RebalanceInProgressException, NotCoordinatorException, or callback exceptions in the same trace.
- Ensure any ConsumerRebalanceListener callbacks return quickly (no blocking I/O); offload slow work to a separate thread and only touch consumer state from the callback thread.
- Tune retry.backoff.ms / retry.backoff.max.ms so transient coordinator movement recovers within the deadline.
- If the issue is during rebalance, check max.poll.interval.ms versus your record-processing time and lower batch size or raise the interval.
Example fix
// before props.put(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, 10000); consumer.commitSync(); // throws TimeoutException on slow cluster // after props.put(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, 60000); props.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, 30000); consumer.commitSync();
Defensive patterns
Strategy: retry
Validate before calling
// No pre-validation prevents a runtime timeout, but you can pre-size timeouts. Properties p = new Properties(); p.put(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, 60000); // default ~60s p.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, 30000); p.put(ConsumerConfig.RETRY_BACKOFF_MS_CONFIG, 500); p.put(ConsumerConfig.RETRY_BACKOFF_MAX_MS_CONFIG, 10000);
Try / catch
// Retry with bounded attempts + exponential backoff for TimeoutException.
int attempts = 0, maxAttempts = 3;
while (true) {
try {
return consumer.position(partition); // or whichever op timed out
} catch (TimeoutException e) {
if (++attempts > maxAttempts) throw e;
long backoff = Math.min(1000L * (1L << attempts), 8000L);
Thread.sleep(backoff);
}
} Prevention
- Set default.api.timeout.ms generously for slow brokers or cold-start metadata fetches.
- Ensure brokers are reachable (network/bootstraps) before issuing operations; most timeouts are connectivity, not logic.
- Keep the consumer's background event loop unblocked: do not run long logic inside ConsumerRebalanceListener callbacks (AsyncKafkaConsumer).
- Distinguish retriable timeouts (broker down) from fatal ones (operation not supported) before retrying.
- Expose timeout as a tunable in your own config so ops can widen it without code changes.
When it happens
Trigger: Any blocking call on the async consumer whose Future does not complete within the timer: commitSync() exceeding default.api.timeout.ms; poll() against an unavailable broker or during a long rebalance; unsubscribe() that cannot finish because a ConsumerRebalanceListener.onPartitionsRevoked callback on the application thread is itself blocking; position(partition) when offset fetch is slow.
Common situations: Broker outage or network partition making the coordinator unreachable; max.poll.interval.ms exceeded so the consumer was kicked out of the group mid-operation; a user-supplied ConsumerRebalanceListener that blocks (DB locks, slow HTTP) and stalls the handoff between background and application threads; default.api.timeout.ms set too low for a slow cluster; GC pauses or overloaded hosts stretching coordinator responses past the deadline.
Related errors
- Failed to get offsets by times in {}ms
- Timeout expired while fetching topic metadata
- Timeout of {}ms expired before the position for partition {}
- Timeout of {}ms expired before the last committed offset for
- Topic collection to subscribe to cannot be null
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/c5834398c437c2c5.json.
Report an issue: GitHub.