{"record":{"id":"a4ad16685d2b0156","repo":"apache/kafka","slug":"the-timeout-cannot-be-negative","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/admin/KafkaAdminClient.java","lineNumber":726,"sourceCode":"        if (defaultApiTimeoutMs < requestTimeoutMs) {\n            if (config.originals().containsKey(AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG)) {\n                throw new ConfigException(\"The specified value of \" + AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG +\n                    \" must be no smaller than the value of \" + AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG + \".\");\n            } else {\n                log.warn(\"Overriding the default value for {} ({}) with the explicitly configured request timeout {}\",\n                    AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, defaultApiTimeoutMs,\n                    requestTimeoutMs);\n                return requestTimeoutMs;\n            }\n        }\n        return defaultApiTimeoutMs;\n    }\n\n    @Override\n    public void close(Duration timeout) {\n        long waitTimeMs = timeout.toMillis();\n        if (waitTimeMs < 0)\n            throw new IllegalArgumentException(\"The timeout cannot be negative.\");\n        waitTimeMs = Math.min(TimeUnit.DAYS.toMillis(365), waitTimeMs); // Limit the timeout to a year.\n        long now = time.milliseconds();\n        long newHardShutdownTimeMs = now + waitTimeMs;\n        long prev = INVALID_SHUTDOWN_TIME;\n        clientTelemetryReporter.ifPresent(ClientTelemetryReporter::initiateClose);\n        metrics.close();\n        while (true) {\n            if (hardShutdownTimeMs.compareAndSet(prev, newHardShutdownTimeMs)) {\n                if (prev == INVALID_SHUTDOWN_TIME) {\n                    log.debug(\"Initiating close operation.\");\n                } else {\n                    log.debug(\"Moving hard shutdown time forward.\");\n                }\n                client.wakeup(); // Wake the thread, if it is blocked inside poll().\n                break;\n            }\n            prev = hardShutdownTimeMs.get();\n            if (prev < newHardShutdownTimeMs) {","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java#L708-L744","documentation":"An IllegalArgumentException thrown by KafkaAdminClient.close(Duration) when the supplied timeout converts to a negative millisecond value. A negative Duration cannot be honored as a wait and indicates a caller bug.","triggerScenarios":"Calling admin.close(Duration.ofMillis(-1)) or admin.close(Duration.ofNanos(-100)). Most commonly, subtracting two timestamps and passing the (negative) difference as the close timeout.","commonSituations":"Computing remaining time before a deadline and passing it without clamping at zero; reusing a deadline Duration that has already elapsed; off-by-one in retry-loop timeout arithmetic.","solutions":["Clamp the computed timeout to zero before calling close: admin.close(duration.compareTo(Duration.ZERO) < 0 ? Duration.ZERO : duration).","Use Admin.DURATION which is non-negative, or pass Duration.ZERO for a non-blocking close.","Compute remaining time with Math.max(0, deadline - now)."],"exampleFix":"// before\nlong remaining = deadlineMs - System.currentTimeMillis(); // can be < 0\nadmin.close(Duration.ofMillis(remaining));\n\n// after\nlong remaining = Math.max(0, deadlineMs - System.currentTimeMillis());\nadmin.close(Duration.ofMillis(remaining));","handlingStrategy":"validation","validationCode":"Duration safe = timeout.isNegative() ? Duration.ZERO : timeout;\nadmin.close(safe);","typeGuard":"static boolean isNonNegative(Duration d) {\n    return d == null || !d.isNegative();\n}","tryCatchPattern":null,"preventionTips":["Always clamp computed remaining-time values at zero before passing to close().","Use Duration.ZERO for a non-blocking close rather than risking a negative value."],"tags":["kafka-admin","lifecycle","timeout","argument-validation"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}