{"id":"11157362cd01eab1","repo":"apache/kafka","slug":"the-timeout-cannot-be-negative-111573","errorCode":null,"errorMessage":"The timeout cannot be negative.","messagePattern":"The timeout cannot be negative\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java","lineNumber":1122,"sourceCode":"        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 wakeup() {\n        this.client.wakeup();\n    }\n\n    @Override\n    public void close(CloseOptions option) {\n        Duration timeout = option.timeout().orElseGet(() -> Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));\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    private Timer createTimerForRequest(final Duration timeout) {\n        // this.time could be null if an exception occurs in constructor prior to setting the this.time field\n        final Time localTime = (time == null) ? Time.SYSTEM : time;\n        return localTime.timer(Math.min(timeout.toMillis(), requestTimeoutMs));\n    }","sourceCodeStart":1104,"sourceCodeEnd":1140,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java#L1104-L1140","documentation":"Thrown by KafkaConsumer.close(CloseOptions) when the configured close timeout is negative. The check is a simple precondition on option.timeout() (or the default DEFAULT_CLOSE_TIMEOUT_MS), since a negative duration is not a meaningful wait. It occurs before any resource cleanup, so no leak is caused.","triggerScenarios":"Constructing CloseOptions.timeout(Duration.ofMillis(-1)); passing a computed Duration that subtracted past zero; serializing a timeout from config that parsed negative; reusing a Duration object that was decremented in a loop.","commonSituations":"Misconfiguring request.timeout.ms or close timeout to a negative number; arithmetic on durations without a floor; copying examples that used a now-removed overload; properties files with negative integers due to typos.","solutions":["Clamp the close timeout to a non-negative value: Duration.ofMillis(Math.max(0, ms)).","Fix the source of the negative number (config typo or bad time math).","Use the no-arg close() or CloseOptions.timeout(Duration.ofSeconds(30)) defaults instead of computing your own."],"exampleFix":"// before\nconsumer.close(new CloseOptions().timeout(Duration.ofMillis(timeoutMs))); // timeoutMs < 0\n\n// after\nlong safe = Math.max(0L, timeoutMs);\nconsumer.close(new CloseOptions().timeout(Duration.ofMillis(safe)));","handlingStrategy":"validation","validationCode":"// Validate the timeout you hand to close(CloseOptions) / close(Duration):\nDuration closeTimeout = option.timeout().orElse(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));\nif (closeTimeout == null || closeTimeout.isNegative()) {\n    closeTimeout = Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS);\n}\nconsumer.close(CloseOptions.timeout(closeTimeout));","typeGuard":"// A guard helper that returns a guaranteed-non-negative Duration:\nstatic Duration nonNegative(Duration d, Duration fallback) {\n    return (d == null || d.isNegative()) ? fallback : d;\n}\n// Usage: consumer.close(nonNegative(configured, Duration.ofSeconds(30)));","tryCatchPattern":"// Treat a negative-timeout close() as a programming error; fall back to the default and retry once:\ntry {\n    consumer.close(opts);\n} catch (IllegalArgumentException e) {\n    if (!e.getMessage().contains(\"timeout cannot be negative\")) throw e;\n    consumer.close(); // default timeout\n}","preventionTips":["Compute close timeouts from absolute configs (Duration.ofMillis(X)) rather than arithmetic on (deadline - now), which can go negative past the deadline.","Clamp every externally-supplied duration through one helper before it touches any Kafka client method.","Unit-test your config layer with a deliberately negative value to prove it gets normalized."],"tags":["consumer","validation","config","java"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}