apache/kafka · error · TimeoutException

Timeout expired after {timeoutMs}ms while awaiting {operatio

Error message

Timeout expired after {timeoutMs}ms while awaiting {operation}. {expectedTimeoutReason}

What it means

Thrown by TransactionalRequestResult.await when the internal CountDownLatch does not reach zero within the configured timeout while waiting for a transactional control RPC (InitProducerId, AddPartitionsToTxn, EndTxn, TxnOffsetCommit, FindCoordinator, AlterProducerEpoch) to be acked by the coordinator. It surfaces as a TimeoutException carrying the elapsed ms, the operation name, and a broker-explained expectedTimeoutReason when the broker has already indicated the operation will take longer (e.g. CommitFailedException-style timing). The producer stays in the pending state and subsequent transactional calls will hit the pending-transition checks (errors 293/294).

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/producer/internals/TransactionalRequestResult.java:54

    private TransactionalRequestResult(CountDownLatch latch, String operation) {
        this.latch = latch;
        this.operation = operation;
    }

    public void fail(RuntimeException error) {
        this.error = error;
        this.latch.countDown();
    }

    public void done() {
        this.latch.countDown();
    }

    public void await(long timeout, TimeUnit unit, String expectedTimeoutReason) {
        try {
            boolean success = latch.await(timeout, unit);
            if (!success) {
                throw new TimeoutException("Timeout expired after " + unit.toMillis(timeout) +
                    "ms while awaiting " + operation + ". " + expectedTimeoutReason);
            }

            isAcked = true;
            if (error != null) {
                throw error;
            }
        } catch (InterruptedException e) {
            throw new InterruptException("Received interrupt while awaiting " + operation, e);
        }
    }

    public RuntimeException error() {
        return error;
    }

    public boolean isSuccessful() {
        return isCompleted() && error == null;

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Increase request.timeout.ms and delivery.timeout.ms (and broker transaction.max.timeout.ms) to exceed realistic RPC latency under peak load.
  2. Verify coordinator health: which broker owns the __transaction_state partition for the transactional.id hash, check its load, GC, and replication status.
  3. Check network path between client and brokers (latency, packet loss, firewall timeouts on idle connections).
  4. If transient, retry the SAME transactional operation (it's pending — see errors 293/294); if persistent, recreate the producer after close().

Example fix

// before
props.put(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG, "30000");  // 30s, too tight under load
props.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, "60000");

// after
props.put(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG, "90000");   // 90s
props.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, "120000");  // 120s
// and on broker: transaction.max.timeout.ms >= 120000
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate timeouts before issuing transactional calls so your own configured
// delivery timeout is not shorter than the work you expect:
long delivery = Long.parseLong(props.getProperty(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, "120000"));
long txn     = Long.parseLong(props.getProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG, "60000"));
if (delivery <= 0 || txn <= 0) throw new IllegalArgumentException("timeouts must be positive");
if (txn > 900000)              throw new IllegalArgumentException("txn timeout exceeds broker max");

Try / catch

try {
    producer.commitTransaction();
} catch (org.apache.kafka.common.errors.TimeoutException e) {
    // Transactional control request did not finish in time. Idempotently retry the same
    // method; the broker deduplicates transaction state transitions.
    try {
        producer.commitTransaction();
    } catch (TimeoutException again) {
        producer.close(Duration.ZERO);
        throw new RuntimeException("Transactional commit timed out twice; broker unreachable", again);
    }
}

Prevention

When it happens

Trigger: KafkaProducer.initTransactions/beginTransaction/commitTransaction/abortTransaction/sendOffsetsToTransaction internally calling TransactionalRequestResult.await and the underlying RPC not completing before the wait deadline. Typical when the coordinator (broker hosting __transaction_state partition for this transactional.id) is slow, unreachable, or rebalancing, or when the client network stalls.

Common situations: transaction.timeout.ms or request.timeout.ms too low; broker coordinator under load or recovering from a controller failover; misconfigured bootstrap servers or DNS issues causing FindCoordinator to hang; transaction.state.log under-replicated; long GC on broker or client; cross-AZ/region latency exceeding the wait; client behind a slow proxy or firewall doing deep packet inspection.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/f25978aa29585160.json. Report an issue: GitHub.