{"id":"d8e4441b00622fbd","repo":"apache/kafka","slug":"timeout-of-ms-expired-before-the-last-committed","errorCode":null,"errorMessage":"Timeout of {}ms expired before the last committed offset for partitions {} could be determined. Try tuning default.api.timeout.ms larger to relax the threshold.","messagePattern":"Timeout of (.+?)ms expired before the last committed offset for partitions (.+?) could be determined\\. Try tuning default\\.api\\.timeout\\.ms larger to relax the threshold\\.","errorType":"exception","errorClass":"org.apache.kafka.common.errors.TimeoutException","httpStatus":null,"severity":"warning","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java","lineNumber":1279,"sourceCode":"    @Override\n    public Map<TopicPartition, OffsetAndMetadata> committed(final Set<TopicPartition> partitions,\n                                                            final Duration timeout) {\n        acquireAndEnsureOpen();\n        long start = time.nanoseconds();\n        try {\n            throwIfGroupIdNotDefined();\n            if (partitions.isEmpty()) {\n                return Collections.emptyMap();\n            }\n\n            final FetchCommittedOffsetsEvent event = new FetchCommittedOffsetsEvent(\n                partitions,\n                calculateDeadlineMs(time, timeout));\n            wakeupTrigger.setActiveTask(event.future());\n            try {\n                return applicationEventHandler.addAndGet(event);\n            } catch (TimeoutException e) {\n                throw new TimeoutException(\"Timeout of \" + timeout.toMillis() + \"ms expired before the last \" +\n                    \"committed offset for partitions \" + partitions + \" could be determined. Try tuning \" +\n                    ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG + \" larger to relax the threshold.\");\n            } finally {\n                wakeupTrigger.clearTask();\n            }\n        } finally {\n            kafkaConsumerMetrics.recordCommitted(time.nanoseconds() - start);\n            release();\n        }\n    }\n\n    private void throwIfGroupIdNotDefined() {\n        if (groupMetadata.get().isEmpty()) {\n            throw new InvalidGroupIdException(\"To use the group management or offset commit APIs, you must \" +\n                \"provide a valid \" + ConsumerConfig.GROUP_ID_CONFIG + \" in the consumer configuration.\");\n        }\n    }\n","sourceCodeStart":1261,"sourceCodeEnd":1297,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java#L1261-L1297","documentation":"TimeoutException thrown by AsyncKafkaConsumer.committed(Set<TopicPartition>, Duration) when applicationEventHandler.addAndGet(FetchCommittedOffsetsEvent) raises a TimeoutException before the group coordinator returns the committed offsets. The wrapper message names the timeout (ms), the requested partitions, and explicitly suggests raising default.api.timeout.ms. committed() requires a valid group.id (throwIfGroupIdNotDefined runs first) and an empty partition set short-circuits.","triggerScenarios":"Calling consumer.committed(partitions, timeout) with a timeout too short for the group coordinator to respond; coordinator unavailable or still loading; consumer not yet joined to the group; broker/network latency exceeding the supplied Duration. The catch re-wraps the inner TimeoutException with the actionable hint.","commonSituations":"Default api timeout overridden too low in tight tests; coordinator rebalancing or just-elected; client connecting to an unreachable/down broker; large partition set with slow offset fetch; running committed() immediately after construction before group join completes; cross-AZ/region latency; running with auto-commit disabled and checking committed offsets in a startup probe.","solutions":["Raise default.api.timeout.ms (the message explicitly recommends this) or pass a larger Duration to committed(partitions, timeout).","Ensure the consumer has joined the group (poll at least once) before calling committed, so the coordinator context is ready.","Check coordinator/broker health and connectivity (bootstrap servers, security, GC), and retry with backoff.","Reduce the partition set passed in if you only need a subset, to lower round-trip cost."],"exampleFix":"// before\nMap<TopicPartition, OffsetAndMetadata> c =\n    consumer.committed(allPartitions, Duration.ofMillis(100));\n\n// after\nprops.put(ConsumerConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, 60000);\n// ... later:\nMap<TopicPartition, OffsetAndMetadata> c =\n    consumer.committed(allPartitions, Duration.ofSeconds(30));","handlingStrategy":"retry","validationCode":"// committed() requires group.id and a non-empty partition set; check both, and\n// size the timeout to your environment.\nstatic Map<TopicPartition, OffsetAndMetadata> safeCommitted(\n        Consumer<?, ?> c, Set<TopicPartition> parts, Duration timeout) {\n    if (c.groupMetadata() == null)\n        throw new IllegalStateException(\"group.id not set; committed() is unavailable\");\n    if (parts == null || parts.isEmpty())\n        return java.util.Collections.emptyMap();\n    if (timeout == null || timeout.isNegative() || timeout.isZero())\n        throw new IllegalArgumentException(\"committed timeout must be positive, got \" + timeout);\n    return c.committed(parts, timeout);\n}\n\n// The error message itself suggests tuning default.api.timeout.ms; pre-flight by\n// ensuring the property is set generously relative to request.timeout.ms:\n//   default.api.timeout.ms  >=  request.timeout.ms + retry.backoff.ms * (retries)\n// A typical safe starting point: request=30s, default.api=60s.","typeGuard":null,"tryCatchPattern":"// TimeoutException from committed() is retriable when the broker is reachable.\n// Retry with backoff; escalate by widening default.api.timeout.ms if it persists.\nint maxAttempts = 3;\nlong[] backoffMs = { 200, 1000, 5000 };\nMap<TopicPartition, OffsetAndMetadata> committed = null;\nfor (int attempt = 0; ; attempt++) {\n    try {\n        committed = consumer.committed(parts, Duration.ofSeconds(30));\n        break;\n    } catch (org.apache.kafka.common.errors.TimeoutException e) {\n        if (attempt >= maxAttempts) {\n            log.error(\"committed() timed out for {} after {} attempts; \" +\n                      \"consider raising default.api.timeout.ms and check group coordinator health\",\n                      parts, attempt);\n            throw e;\n        }\n        log.warn(\"committed({}) timed out (attempt {}/{}); backing off {}ms\",\n                 parts, attempt + 1, maxAttempts, backoffMs[attempt]);\n        try { Thread.sleep(backoffMs[attempt]); } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new org.apache.kafka.common.errors.InterruptedException(ie);\n        }\n    }\n}","preventionTips":["Only call committed() after subscribe()+poll() has completed the first join group; querying committed offsets mid-rebalance is the most common cause of the timeout.","Set default.api.timeout.ms comfortably larger than request.timeout.ms (e.g. 2x) so a single broker hiccup doesn't trip the higher threshold.","Use committed(partitions, Duration) with an explicit timeout so you control the budget rather than inheriting a misconfigured default.","Monitor the group coordinator's load and the consumer's rebalance rate; frequent rebalances make committed() chronically slow.","Cache committed offsets for the duration of a single processing batch if you call committed() in a hot loop; re-querying per record amplifies any broker latency into timeouts."],"tags":["consumer","committed-offsets","timeout","coordinator","network"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}