apache/kafka · error · IllegalStateException

Invalid attempt to complete a request future which is alread

Error message

Invalid attempt to complete a request future which is already complete

What it means

Thrown by RequestFuture.complete(T value) when the CAS result.compareAndSet(INCOMPLETE_SENTINEL, value) fails because the future already holds a terminal value (either a success value or a failure exception). A RequestFuture is single-shot; once complete() or raise() has run, the result cannot be overwritten. Attempting to complete it again indicates a double-completion bug in the calling code.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/RequestFuture.java:128

        if (!failed())
            throw new IllegalStateException("Attempt to retrieve exception from future which hasn't failed");
        return (RuntimeException) result.get();
    }

    /**
     * Complete the request successfully. After this call, {@link #succeeded()} will return true
     * and the value can be obtained through {@link #value()}.
     * @param value corresponding value (or null if there is none)
     * @throws IllegalStateException if the future has already been completed
     * @throws IllegalArgumentException if the argument is an instance of {@link RuntimeException}
     */
    public void complete(T value) {
        try {
            if (value instanceof RuntimeException)
                throw new IllegalArgumentException("The argument to complete can not be an instance of RuntimeException");

            if (!result.compareAndSet(INCOMPLETE_SENTINEL, value))
                throw new IllegalStateException("Invalid attempt to complete a request future which is already complete");
            fireSuccess();
        } finally {
            completedLatch.countDown();
        }
    }

    /**
     * Raise an exception. The request will be marked as failed, and the caller can either
     * handle the exception or throw it.
     * @param e corresponding exception to be passed to caller
     * @throws IllegalStateException if the future has already been completed
     */
    public void raise(RuntimeException e) {
        try {
            if (e == null)
                throw new IllegalArgumentException("The exception passed to raise must not be null");

            if (!result.compareAndSet(INCOMPLETE_SENTINEL, e))

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Gate every completion site on if (!future.isDone()) before calling complete() (or use compareAndSet yourself).
  2. Eliminate the second completion path; a future should have exactly one owner that completes it.
  3. If a timeout path is needed, cancel the in-flight request and complete once from a single winsite guarded by isDone().

Example fix

// before
future.complete(value); // may run after network layer already completed it

// after
if (!future.isDone()) {
    future.complete(value);
}
Defensive patterns

Strategy: validation

Validate before calling

// Never call complete() without confirming the future is still incomplete.
if (!future.isDone()) {
    future.complete(value);
} else {
    // already terminal; ignore or log — do not attempt to complete again
}

Try / catch

try {
    future.complete(value);
} catch (IllegalStateException ex) {
    // future was already completed; safe to ignore since terminal state is already set
}

Prevention

When it happens

Trigger: Two code paths racing to complete the same future (e.g. a success callback and a timeout handler firing in the same poll loop); a listener registered via addListener() that calls complete() on the already-completed source; manually calling complete() after the network layer already completed the future.

Common situations: Adding a deadline/timeout future completion on top of the existing network completion without deduplication; chaining futures with chain() or compose() and then also completing the source; refactors that surface a second completion site.

Related errors


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