apache/kafka · error · java.lang.IllegalArgumentException

The timeout cannot be negative.

Error message

The timeout cannot be negative.

What it means

IllegalArgumentException thrown by close(CloseOptions) when the configured close timeout is negative. A negative Duration is meaningless for a graceful shutdown window, so the consumer rejects it before acquiring the instance lock and attempting any close logic. The check uses timeout.toMillis() < 0, so any negative duration (nanoseconds-negative) triggers it.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java:1563

    }

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

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

    @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();
        }
    }

    /**
     * Please keep these tenets in mind for the implementation of the {@link AsyncKafkaConsumer}’s
     * {@link #close(Duration)} method. In the future, these tenets may be made officially part of the top-level
     * {@link KafkaConsumer#close(Duration)} API, but for now they remain here.
     *

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Pass a non-negative Duration; use Duration.ZERO for immediate close or the default DEFAULT_CLOSE_TIMEOUT_MS (30 s) for graceful close.
  2. If the duration is computed, clamp it: timeout = timeout.negated() ? Duration.ZERO : timeout, or Math.max(0, ms).
  3. Audit the source config (e.g. consumer.close.timeout.ms in a wrapper) and ensure it is >= 0.

Example fix

// before
consumer.close(CloseOptions.timeout(Duration.ofMillis(-1)));

// after
consumer.close(CloseOptions.timeout(Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS)));
Defensive patterns

Strategy: validation

Validate before calling

Duration closeTimeout = ...;
if (closeTimeout == null || closeTimeout.isNegative()) {
    closeTimeout = Duration.ofMillis(DEFAULT_CLOSE_TIMEOUT_MS); // or throw IllegalArgumentException
}
consumer.close(closeTimeout);

Prevention

When it happens

Trigger: Calling consumer.close(CloseOptions.timeout(Duration.ofMillis(-1))), or the deprecated close(Duration) with a negative duration, or close() / close(timeout) where the timeout originates from a config that was parsed as negative (e.g. exit.timeout.ms or a derived value).

Common situations: Misconfigured shutdown timeout properties; arithmetic that subtracts elapsed time from a budget and goes negative; frameworks that pass a 'sentinel' negative value to mean 'wait forever' (this consumer does not honor that convention); copy-paste from code that used -1 elsewhere.

Related errors


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