{"id":"bc6b730cd49547b6","repo":"apache/kafka","slug":"the-timeout-cannot-be-negative-bc6b73","errorCode":null,"errorMessage":"The timeout cannot be negative.","messagePattern":"The timeout cannot be negative\\.","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java","lineNumber":1563,"sourceCode":"    }\n\n    @Override\n    public void close() {\n        close(CloseOptions.timeout(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS)));\n    }\n\n    @Deprecated\n    @Override\n    public void close(Duration timeout) {\n        close(CloseOptions.timeout(timeout));\n    }\n\n    @Override\n    public void close(CloseOptions option) {\n        Duration timeout = option.timeout().orElseGet(() -> Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));\n\n        if (timeout.toMillis() < 0)\n            throw new IllegalArgumentException(\"The timeout cannot be negative.\");\n        acquire();\n        try {\n            if (!closed) {\n                // need to close before setting the flag since the close function\n                // itself may trigger rebalance callback that needs the consumer to be open still\n                close(timeout, option.groupMembershipOperation(), false);\n            }\n        } finally {\n            closed = true;\n            release();\n        }\n    }\n\n    /**\n     * Please keep these tenets in mind for the implementation of the {@link AsyncKafkaConsumer}’s\n     * {@link #close(Duration)} method. In the future, these tenets may be made officially part of the top-level\n     * {@link KafkaConsumer#close(Duration)} API, but for now they remain here.\n     *","sourceCodeStart":1545,"sourceCodeEnd":1581,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java#L1545-L1581","documentation":"IllegalArgumentException thrown by close(CloseOptions) when the configured close timeout is negative. A negative Duration is meaningless for a graceful shutdown window, so the consumer rejects it before acquiring the instance lock and attempting any close logic. The check uses timeout.toMillis() < 0, so any negative duration (nanoseconds-negative) triggers it.","triggerScenarios":"Calling consumer.close(CloseOptions.timeout(Duration.ofMillis(-1))), or the deprecated close(Duration) with a negative duration, or close() / close(timeout) where the timeout originates from a config that was parsed as negative (e.g. exit.timeout.ms or a derived value).","commonSituations":"Misconfigured shutdown timeout properties; arithmetic that subtracts elapsed time from a budget and goes negative; frameworks that pass a 'sentinel' negative value to mean 'wait forever' (this consumer does not honor that convention); copy-paste from code that used -1 elsewhere.","solutions":["Pass a non-negative Duration; use Duration.ZERO for immediate close or the default DEFAULT_CLOSE_TIMEOUT_MS (30 s) for graceful close.","If the duration is computed, clamp it: timeout = timeout.negated() ? Duration.ZERO : timeout, or Math.max(0, ms).","Audit the source config (e.g. consumer.close.timeout.ms in a wrapper) and ensure it is >= 0."],"exampleFix":"// before\nconsumer.close(CloseOptions.timeout(Duration.ofMillis(-1)));\n\n// after\nconsumer.close(CloseOptions.timeout(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS)));","handlingStrategy":"validation","validationCode":"Duration closeTimeout = ...;\nif (closeTimeout == null || closeTimeout.isNegative()) {\n    closeTimeout = Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS); // or throw IllegalArgumentException\n}\nconsumer.close(closeTimeout);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["KafkaConsumer.close(Duration) throws IllegalArgumentException for any negative duration; validate before calling.","Prefer close(CloseOptions) or the no-arg close() to inherit the safe default close timeout.","Reject negative timeouts at your config boundary so they never reach the client."],"tags":["kafka","consumer","lifecycle","validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}