apache/kafka · error · IllegalArgumentException

The timeout cannot be negative.

Error message

The timeout cannot be negative.

What it means

Thrown by KafkaConsumer.close(CloseOptions) when the configured close timeout is negative. The check is a simple precondition on option.timeout() (or the default DEFAULT_CLOSE_TIMEOUT_MS), since a negative duration is not a meaningful wait. It occurs before any resource cleanup, so no leak is caused.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java:1122

        close(CloseOptions.timeout(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS)));
    }

    @Deprecated
    @Override
    public void close(Duration timeout) {
        close(CloseOptions.timeout(timeout));
    }

    @Override
    public void wakeup() {
        this.client.wakeup();
    }

    @Override
    public void close(CloseOptions option) {
        Duration timeout = option.timeout().orElseGet(() -> Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));
        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 rebalance callback that needs the consumer to be open still
                close(timeout, option.groupMembershipOperation(), false);
            }
        } finally {
            closed = true;
            release();
        }
    }

    private Timer createTimerForRequest(final Duration timeout) {
        // this.time could be null if an exception occurs in constructor prior to setting the this.time field
        final Time localTime = (time == null) ? Time.SYSTEM : time;
        return localTime.timer(Math.min(timeout.toMillis(), requestTimeoutMs));
    }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Clamp the close timeout to a non-negative value: Duration.ofMillis(Math.max(0, ms)).
  2. Fix the source of the negative number (config typo or bad time math).
  3. Use the no-arg close() or CloseOptions.timeout(Duration.ofSeconds(30)) defaults instead of computing your own.

Example fix

// before
consumer.close(new CloseOptions().timeout(Duration.ofMillis(timeoutMs))); // timeoutMs < 0

// after
long safe = Math.max(0L, timeoutMs);
consumer.close(new CloseOptions().timeout(Duration.ofMillis(safe)));
Defensive patterns

Strategy: validation

Validate before calling

// Validate the timeout you hand to close(CloseOptions) / close(Duration):
Duration closeTimeout = option.timeout().orElse(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS));
if (closeTimeout == null || closeTimeout.isNegative()) {
    closeTimeout = Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS);
}
consumer.close(CloseOptions.timeout(closeTimeout));

Type guard

// A guard helper that returns a guaranteed-non-negative Duration:
static Duration nonNegative(Duration d, Duration fallback) {
    return (d == null || d.isNegative()) ? fallback : d;
}
// Usage: consumer.close(nonNegative(configured, Duration.ofSeconds(30)));

Try / catch

// Treat a negative-timeout close() as a programming error; fall back to the default and retry once:
try {
    consumer.close(opts);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("timeout cannot be negative")) throw e;
    consumer.close(); // default timeout
}

Prevention

When it happens

Trigger: Constructing CloseOptions.timeout(Duration.ofMillis(-1)); passing a computed Duration that subtracted past zero; serializing a timeout from config that parsed negative; reusing a Duration object that was decremented in a loop.

Common situations: Misconfiguring request.timeout.ms or close timeout to a negative number; arithmetic on durations without a floor; copying examples that used a now-removed overload; properties files with negative integers due to typos.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/11157362cd01eab1.json. Report an issue: GitHub.