apache/kafka · error · IllegalArgumentException
The timeout cannot be negative.
Error message
The timeout cannot be negative.
What it means
Thrown by ShareConsumerImpl.close(Duration) (line 1001) when timeout.toMillis() < 0. The share consumer validates the close timeout up front because negative durations are programming errors (not user input) and would propagate into the network-thread shutdown logic as illegal wait times. It fails fast with IllegalArgumentException rather than hanging or silently coercing to zero.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java:1001
log.debug("Skipping unregistration for metric {}. Existing consumer metrics cannot be removed.", metric.metricName());
}
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
close(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));
}
/**
* {@inheritDoc}
*/
@Override
public void close(final Duration timeout) {
if (timeout.toMillis() < 0)
throw new IllegalArgumentException("The timeout cannot be negative.");
acquire();
try {
if (!closed) {
// need to close before setting the flag since the close function
// itself may trigger code that needs the consumer to be open still
close(timeout, false);
}
} finally {
closed = true;
release();
}
}
private void close(final Duration timeout, final boolean swallowException) {
log.trace("Closing the Kafka consumer");
AtomicReference<Throwable> firstException = new AtomicReference<>();
// We are already closing with a timeout, don't allow wake-ups from here on.View on GitHub (pinned to c31c9215e1)
Solutions
- Pass a non-negative Duration, e.g. consumer.close(Duration.ofSeconds(30)).
- If computing remaining time, clamp it to zero: Duration d = remaining.isNegative() ? Duration.ZERO : remaining.
- Use the no-arg close() which uses DEFAULT_CLOSE_TIMEOUT_MS when you do not need a custom timeout.
- Validate the source of the Duration value — log it before close to find where the negative number originates.
Example fix
// before consumer.close(deadline.minus(now)); // after Duration remaining = Duration.between(now, deadline); consumer.close(remaining.isNegative() ? Duration.ZERO : remaining);
Defensive patterns
Strategy: validation
Validate before calling
// Validate the timeout passed to close(Duration) before invoking it.
java.time.Duration closeTimeout = /* user value */;
if (closeTimeout == null || closeTimeout.toMillis() < 0) {
throw new IllegalArgumentException("close timeout must be non-negative");
}
consumer.close(closeTimeout); Type guard
null
Try / catch
null
Prevention
- Never compute close timeouts from subtraction that can underflow (e.g. deadline - now).
- Prefer Duration.ZERO over negative durations to signal an immediate close.
- When in doubt, call the no-arg close() which uses the default positive timeout.
When it happens
Trigger: Calling consumer.close(Duration.ofMillis(-1)) or close(Duration.ofSeconds(-5)). Also reached when a wrapper computes the timeout from a subtraction that underflows (e.g. deadline.minus(other)), or when try-with-resources passes a cached Duration object that was built with a negative value.
Common situations: Code that computes remaining time as start.plus(requested).minus(now) before the deadline has elapsed, yielding a negative span; unit confusion (passing microseconds-as-millis); copy-pasting a poll timeout into close() where the source happened to be negative; framework shutdown hooks (Spring @PreDestroy) that derive timeout from a misconfigured property.
Related errors
- Invalid value `{}` for configuration {}. The value must eith
- Invalid value `{}` for configuration {}. The value must eith
- Failed to close Kafka share consumer
- This consumer has already been closed.
- Invalid url in bootstrap.servers: {url}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/e2be3a5c493e3322.json.
Report an issue: GitHub.