eclipse-vertx/vert.x · error · IllegalStateException

Request already complete

Error message

Request already complete

What it means

checkEnded() throws this IllegalStateException whenever an operation that writes or mutates the request (e.g. setStreamPriority) is invoked after the request has already been completed (trailers sent). Once the request is fully sent, its state can no longer change.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java:606

        uri = "/";
      }
      HttpRequestHead head = new HttpRequestHead(ssl ? "https" : "http", method, uri, headers, authority(), absoluteURI(), traceOperation);
      future = stream.writeHead(head, chunked, buff, writeEnd, priority, connect);
    } else {
      if (buff == null && !end) {
        throw new IllegalArgumentException();
      }
      future = stream.writeChunk(buff, writeEnd);
    }
    if (end) {
      tryComplete();
    }
    return future;
  }

  private void checkEnded() {
    if (trailersSent) {
      throw new IllegalStateException("Request already complete");
    }
  }

  @Override
  public synchronized HttpClientRequest setStreamPriority(StreamPriority priority) {
    if (headersSent) {
      stream.updatePriority(priority);
    } else {
      this.priority = priority;
    }
    return this;
  }

  @Override
  public synchronized StreamPriority getStreamPriority() {
    return stream.priority();
  }
}

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Reorder code so priority/headers are set before end() is called
  2. Track request completion (e.g. a boolean or the end future) and skip further mutations once ended
  3. Only call end() once, from a single code path

Example fix

// before
request.end();
request.setStreamPriority(priority); // throws
// after
request.setStreamPriority(priority);
request.end();
Defensive patterns

Strategy: type-guard

Validate before calling

boolean ended = endFuture.isComplete();
if (!ended) { request.setStreamPriority(priority); }

Type guard

void safeSetPriority(HttpClientRequest req, StreamPriority p, Future<Void> endFuture) {
  if (!endFuture.isComplete()) req.setStreamPriority(p);
}

Try / catch

try {
  request.setStreamPriority(priority);
} catch (IllegalStateException e) {
  // request already complete; ignore or log
}

Prevention

When it happens

Trigger: Calling setStreamPriority, write, putHeader or similar after end()/end(chunk) has completed, e.g. asynchronously after a delayed callback fires post-completion.

Common situations: Async code that configures the request after awaiting something, while the request already ended due to an error path or early completion; duplicated completion paths calling end twice.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/9e51fff68291e54d. Report an issue: GitHub.