{"id":"1954cf205a5144ae","repo":"apache/kafka","slug":"timeout-needs-to-be-greater-than-0","errorCode":null,"errorMessage":"Timeout needs to be greater than 0","messagePattern":"Timeout needs to be greater than 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/NetworkClientUtils.java","lineNumber":61,"sourceCode":"        client.poll(0, currentTime);\n        return client.isReady(node, currentTime);\n    }\n\n    /**\n     * Invokes `client.poll` to discard pending disconnects, followed by `client.ready` and 0 or more `client.poll`\n     * invocations until the connection to `node` is ready, the timeoutMs expires or the connection fails.\n     *\n     * It returns `true` if the call completes normally or `false` if the timeoutMs expires. If the connection fails,\n     * an `IOException` is thrown instead. Note that if the `NetworkClient` has been configured with a positive\n     * connection timeoutMs, it is possible for this method to raise an `IOException` for a previous connection which\n     * has recently disconnected. If authentication to the node fails, an `AuthenticationException` is thrown.\n     *\n     * This method is useful for implementing blocking behaviour on top of the non-blocking `NetworkClient`, use it with\n     * care.\n     */\n    public static boolean awaitReady(KafkaClient client, Node node, Time time, long timeoutMs) throws IOException {\n        if (timeoutMs < 0) {\n            throw new IllegalArgumentException(\"Timeout needs to be greater than 0\");\n        }\n        long startTime = time.milliseconds();\n\n        if (isReady(client, node, startTime) ||  client.ready(node, startTime))\n            return true;\n\n        long attemptStartTime = time.milliseconds();\n        while (!client.isReady(node, attemptStartTime) && attemptStartTime - startTime < timeoutMs) {\n            if (client.connectionFailed(node)) {\n                throw new IOException(\"Connection to \" + node + \" failed.\");\n            }\n            long pollTimeout = timeoutMs - (attemptStartTime - startTime); // initialize in this order to avoid overflow\n\n            // If the network client is waiting to send data for some reason (eg. throttling or retry backoff),\n            // polling longer than that is potentially dangerous as the producer will not attempt to send\n            // any pending requests.\n            long waitingTime = client.pollDelayMs(node, startTime);\n            if (waitingTime > 0 && pollTimeout > waitingTime) {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/NetworkClientUtils.java#L43-L79","documentation":"Thrown as IllegalArgumentException by NetworkClientUtils.awaitReady when the supplied timeoutMs is negative. awaitReady blocks on the non-blocking NetworkClient until the node is ready, so a negative timeout is treated as a programming error rather than a wait request. The check runs before any polling, so the exception is raised immediately on entry.","triggerScenarios":"Calling NetworkClientUtils.awaitReady(client, node, time, timeoutMs) with timeoutMs < 0. This is invoked by callers that wrap the non-blocking client in blocking semantics (some admin/inner client paths). A negative value comes from arithmetic underflow, a misconfigured timeout, or a caller passing a sentinel such as -1.","commonSituations":"Caller computes timeout as (deadline - now) where now is past the deadline, yielding a negative; passing a configured 'unlimited' sentinel of -1 into awaitReady instead of Long.MAX_VALUE; misconfigured request.timeout.ms / reconnect backoff expressed as a negative; tests that pass a literal negative.","solutions":["Pass a non-negative timeout; use Long.MAX_VALUE (or a very large value) for an effectively-unbounded wait instead of -1.","Compute timeout defensively as Math.max(0, deadline - now) at the call site.","Validate externalized timeout configs at startup and fail fast with a clearer error.","Review the caller chain that produced the negative value; it usually indicates the deadline already expired upstream."],"exampleFix":"// before\nlong remaining = deadlineMs - System.currentTimeMillis();\nNetworkClientUtils.awaitReady(client, node, time, remaining);\n// after\nlong remaining = Math.max(0, deadlineMs - System.currentTimeMillis());\nNetworkClientUtils.awaitReady(client, node, time, remaining);","handlingStrategy":"validation","validationCode":"// Validate the timeout before calling NetworkClientUtils.awaitReady(client, node, time, timeoutMs).\npublic static long awaitReadySafe(KafkaClient client, Node node, Time time, long timeoutMs) throws java.io.IOException {\n    if (timeoutMs < 0) {\n        throw new IllegalArgumentException(\n            \"timeoutMs must be >= 0; got \" + timeoutMs\n            + \". Use 0 for a non-blocking readiness check.\");\n    }\n    return NetworkClientUtils.awaitReady(client, node, time, timeoutMs) ? timeoutMs : -1L;\n}","typeGuard":"// Force timeouts through a non-negative typed wrapper.\npublic final class NonNegativeTimeout {\n    public final long ms;\n    public NonNegativeTimeout(long ms) {\n        if (ms < 0) throw new IllegalArgumentException(\"timeout must be >= 0, got \" + ms);\n        this.ms = ms;\n    }\n}\n// Usage: new NonNegativeTimeout(userTimeout).ms","tryCatchPattern":"try {\n    NetworkClientUtils.awaitReady(client, node, time, timeoutMs);\n} catch (IllegalArgumentException e) {\n    if (\"Timeout needs to be greater than 0\".equals(e.getMessage())) {\n    // Programming bug, not a runtime condition. Clamp to 0 or surface a config error;\n    // do not retry with the same value.\n    timeoutMs = Math.max(0, timeoutMs);\n    }\n    throw e;\n}","preventionTips":["awaitReady accepts 0 (non-blocking) and positive values; only negatives are rejected.","Compute timeouts as (deadline - now), never as (now - deadline) — clock skew can flip the sign.","Centralize timeout construction in one helper that clamps to >= 0.","Treat this IllegalArgumentException as a programmer error; it should never reach production."],"tags":["config","timeout","illegal-argument","argument-validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}