{"id":"5bf645c2c7bbb92b","repo":"apache/kafka","slug":"timeout-of-ms-expired-before-successfully-commit","errorCode":null,"errorMessage":"Timeout of {}ms expired before successfully committing offsets {}","messagePattern":"Timeout of (.+?)ms expired before successfully committing offsets (.+?)","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java","lineNumber":762,"sourceCode":"    @Override\n    public void commitSync(Duration timeout) {\n        commitSync(subscriptions.allConsumed(), timeout);\n    }\n\n    @Override\n    public void commitSync(final Map<TopicPartition, OffsetAndMetadata> offsets) {\n        commitSync(offsets, Duration.ofMillis(defaultApiTimeoutMs));\n    }\n\n    @Override\n    public void commitSync(final Map<TopicPartition, OffsetAndMetadata> offsets, final Duration timeout) {\n        acquireAndEnsureOpen();\n        long commitStart = time.nanoseconds();\n        try {\n            throwIfGroupIdNotDefined();\n            offsets.forEach(this::updateLastSeenEpochIfNewer);\n            if (!coordinator.commitOffsetsSync(new HashMap<>(offsets), time.timer(timeout))) {\n                throw new TimeoutException(\"Timeout of \" + timeout.toMillis() + \"ms expired before successfully \" +\n                        \"committing offsets \" + offsets);\n            }\n        } finally {\n            kafkaConsumerMetrics.recordCommitSync(time.nanoseconds() - commitStart);\n            release();\n        }\n    }\n\n    @Override\n    public void commitAsync() {\n        commitAsync(null);\n    }\n\n    @Override\n    public void commitAsync(OffsetCommitCallback callback) {\n        commitAsync(subscriptions.allConsumed(), callback);\n    }\n","sourceCodeStart":744,"sourceCodeEnd":780,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java#L744-L780","documentation":"Thrown as TimeoutException from commitSync when coordinator.commitOffsetsSync returns false, meaning the default-api-timeout or the explicitly passed Duration elapsed before the broker acknowledged the OffsetCommit. It signals the offset commit did not complete within the user-supplied budget; offsets were not durably committed and at-least-once consumption risk remains.","triggerScenarios":"Calling commitSync(offsets, Duration.ofMillis(N)) with N too small for the broker round-trip. Broker unavailable or slow, group coordinator reassigning, network partition, consumer rebalance in progress, or the request queue backed up. Default api.timeout.ms too low for the deployment.","commonSituations":"Production environment with broker GC pauses or controller failover. Cross-AZ/region latency pushing commit beyond default 60s. Committing a large offsets map during a rebalance. Tight timeout chosen to fail fast without considering broker response time.","solutions":["Increase the timeout passed to commitSync (or raise default.api.timeout.ms / request.timeout.ms) to accommodate broker latency.","Investigate broker/group-coordinator health, GC, and network latency; commit timeouts are usually a symptom, not the root cause.","Switch to commitAsync for non-critical commits, or retry commitSync with backoff inside an application-level loop while handling WakeupException.","Reduce the size of the offsets map being committed and ensure no rebalance is in flight (consider adjusting max.poll.interval-ms)."],"exampleFix":"// before\nconsumer.commitSync(offsets, Duration.ofMillis(5000)); // frequently times out\n\n// after\nconsumer.commitSync(offsets, Duration.ofMillis(60000)); // or rely on default.api.timeout.ms\n// plus: tune max.poll.interval.ms, session.timeout.ms; check broker/coordinator health","handlingStrategy":"retry","validationCode":"// Choose a timeout larger than the broker's default; check group coordinator reachability first\nlong commitTimeoutMs = Math.max(\n    (long) consumerProps.getOrDefault(\"default.api.timeout.ms\", 60000),\n    requestTimeoutMs * 3);\nconsumer.commitSync(offsets, java.time.Duration.ofMillis(commitTimeoutMs));","typeGuard":"// Validate offsets are well-formed and within log bounds before committing\nstatic boolean offsetsCommittable(java.util.Map<org.apache.kafka.common.TopicPartition, org.apache.kafka.clients.consumer.OffsetAndMetadata> offsets) {\n    return offsets.entrySet().stream().allMatch(e ->\n        e.getKey() != null && e.getValue() != null && e.getValue().offset() >= 0);\n}","tryCatchPattern":"int maxAttempts = 3;\nfor (int attempt = 1; attempt <= maxAttempts; attempt++) {\n    try {\n        consumer.commitSync(offsets, java.time.Duration.ofMillis(timeoutMs));\n        break;\n    } catch (org.apache.kafka.common.errors.TimeoutException e) {\n        if (attempt == maxAttempts) throw e;\n        // backoff before retry; the broker may recover\n        Thread.sleep(backoffMs * attempt);\n    }\n}","preventionTips":["commitSync fails only when the timeout elapses before the broker acknowledges; raise the timeout or retry with backoff","Prefer commitAsync for at-least-once pipelines and reconcile offsets separately to avoid blocking the poll loop","Check broker/group-coordinator health and request.timeout.ms vs default.api.timeout.ms ratio","Ensure group coordinator is reachable and not under rebalance storm before calling commitSync"],"tags":["consumer","commit","timeout","coordinator","network"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}