apache/kafka · error · IllegalArgumentException
Timeout needs to be greater than 0
Error message
Timeout needs to be greater than 0
What it means
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.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/NetworkClientUtils.java:61
client.poll(0, currentTime);
return client.isReady(node, currentTime);
}
/**
* Invokes `client.poll` to discard pending disconnects, followed by `client.ready` and 0 or more `client.poll`
* invocations until the connection to `node` is ready, the timeoutMs expires or the connection fails.
*
* It returns `true` if the call completes normally or `false` if the timeoutMs expires. If the connection fails,
* an `IOException` is thrown instead. Note that if the `NetworkClient` has been configured with a positive
* connection timeoutMs, it is possible for this method to raise an `IOException` for a previous connection which
* has recently disconnected. If authentication to the node fails, an `AuthenticationException` is thrown.
*
* This method is useful for implementing blocking behaviour on top of the non-blocking `NetworkClient`, use it with
* care.
*/
public static boolean awaitReady(KafkaClient client, Node node, Time time, long timeoutMs) throws IOException {
if (timeoutMs < 0) {
throw new IllegalArgumentException("Timeout needs to be greater than 0");
}
long startTime = time.milliseconds();
if (isReady(client, node, startTime) || client.ready(node, startTime))
return true;
long attemptStartTime = time.milliseconds();
while (!client.isReady(node, attemptStartTime) && attemptStartTime - startTime < timeoutMs) {
if (client.connectionFailed(node)) {
throw new IOException("Connection to " + node + " failed.");
}
long pollTimeout = timeoutMs - (attemptStartTime - startTime); // initialize in this order to avoid overflow
// If the network client is waiting to send data for some reason (eg. throttling or retry backoff),
// polling longer than that is potentially dangerous as the producer will not attempt to send
// any pending requests.
long waitingTime = client.pollDelayMs(node, startTime);
if (waitingTime > 0 && pollTimeout > waitingTime) {View on GitHub (pinned to c31c9215e1)
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.
Example fix
// before long remaining = deadlineMs - System.currentTimeMillis(); NetworkClientUtils.awaitReady(client, node, time, remaining); // after long remaining = Math.max(0, deadlineMs - System.currentTimeMillis()); NetworkClientUtils.awaitReady(client, node, time, remaining);
Defensive patterns
Strategy: validation
Validate before calling
// Validate the timeout before calling NetworkClientUtils.awaitReady(client, node, time, timeoutMs).
public static long awaitReadySafe(KafkaClient client, Node node, Time time, long timeoutMs) throws java.io.IOException {
if (timeoutMs < 0) {
throw new IllegalArgumentException(
"timeoutMs must be >= 0; got " + timeoutMs
+ ". Use 0 for a non-blocking readiness check.");
}
return NetworkClientUtils.awaitReady(client, node, time, timeoutMs) ? timeoutMs : -1L;
} Type guard
// Force timeouts through a non-negative typed wrapper.
public final class NonNegativeTimeout {
public final long ms;
public NonNegativeTimeout(long ms) {
if (ms < 0) throw new IllegalArgumentException("timeout must be >= 0, got " + ms);
this.ms = ms;
}
}
// Usage: new NonNegativeTimeout(userTimeout).ms Try / catch
try {
NetworkClientUtils.awaitReady(client, node, time, timeoutMs);
} catch (IllegalArgumentException e) {
if ("Timeout needs to be greater than 0".equals(e.getMessage())) {
// Programming bug, not a runtime condition. Clamp to 0 or surface a config error;
// do not retry with the same value.
timeoutMs = Math.max(0, timeoutMs);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Illegal MetadataRecoveryStrategy: {name}
- The timeout cannot be negative.
- Invalid url in bootstrap.servers: {url}
- Invalid url in bootstrap.servers: {url}
- Invalid port in bootstrap.servers: {url}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/1954cf205a5144ae.json.
Report an issue: GitHub.