apache/kafka · error · IllegalArgumentException
The timeout cannot be negative.
Error message
The timeout cannot be negative.
What it means
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.
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).
Example fix
// before long remaining = deadlineMs - System.currentTimeMillis(); // can be < 0 admin.close(Duration.ofMillis(remaining)); // after long remaining = Math.max(0, deadlineMs - System.currentTimeMillis()); admin.close(Duration.ofMillis(remaining));
Defensive patterns
Strategy: validation
Validate before calling
Duration safe = timeout.isNegative() ? Duration.ZERO : timeout; admin.close(safe);
Type guard
static boolean isNonNegative(Duration d) {
return d == null || !d.isNegative();
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Cannot request fenced brokers from controller endpoint
- Cannot specify a negative version level.
- Expected minVersionLevel >= 0, maxVersionLevel >= 0 and…
- Failed to create new KafkaAdminClient
- Group ID not found
AI-assisted analysis of apache/kafka@996fb4585a (2026-08-11).
Data as JSON: /api/errors/a4ad16685d2b0156.
Report an issue: GitHub.
Appendix: source
Thrown at clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java:726
if (defaultApiTimeoutMs < requestTimeoutMs) {
if (config.originals().containsKey(AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG)) {
throw new ConfigException("The specified value of " + AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG +
" must be no smaller than the value of " + AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG + ".");
} else {
log.warn("Overriding the default value for {} ({}) with the explicitly configured request timeout {}",
AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG, defaultApiTimeoutMs,
requestTimeoutMs);
return requestTimeoutMs;
}
}
return defaultApiTimeoutMs;
}
@Override
public void close(Duration timeout) {
long waitTimeMs = timeout.toMillis();
if (waitTimeMs < 0)
throw new IllegalArgumentException("The timeout cannot be negative.");
waitTimeMs = Math.min(TimeUnit.DAYS.toMillis(365), waitTimeMs); // Limit the timeout to a year.
long now = time.milliseconds();
long newHardShutdownTimeMs = now + waitTimeMs;
long prev = INVALID_SHUTDOWN_TIME;
clientTelemetryReporter.ifPresent(ClientTelemetryReporter::initiateClose);
metrics.close();
while (true) {
if (hardShutdownTimeMs.compareAndSet(prev, newHardShutdownTimeMs)) {
if (prev == INVALID_SHUTDOWN_TIME) {
log.debug("Initiating close operation.");
} else {
log.debug("Moving hard shutdown time forward.");
}
client.wakeup(); // Wake the thread, if it is blocked inside poll().
break;
}
prev = hardShutdownTimeMs.get();
if (prev < newHardShutdownTimeMs) {View on GitHub (pinned to 996fb4585a)