eclipse-vertx/vert.x · error · IllegalStateException
Client is closed
Error message
Client is closed
What it means
HttpClientBase.checkClosed throws IllegalStateException when the client's close sequence has already started and an operation (request creation, connect, websocket, etc.) is attempted on the closed client. Vert.x clients are not reusable after close.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientBase.java:134
options = options.copy();
setDefaultSslOptions(options);
return Future.succeededFuture(true);
}
protected abstract void setDefaultSslOptions(ClientSSLOptions options);
public HttpClientBase proxyFilter(Predicate<SocketAddress> filter) {
proxyFilter = filter;
return this;
}
public VertxInternal vertx() {
return vertx;
}
protected void checkClosed() {
if (closeSequence.started()) {
throw new IllegalStateException("Client is closed");
}
}
}
View on GitHub (pinned to fb308bd8c3)
Solutions
- Create a new HttpClient instance instead of using the closed one.
- Check client's closeFuture.isComplete() (or guard with isClosed state) before issuing requests.
- Ensure lifecycle ordering: stop schedulers/consumers before closing the client.
- Catch IllegalStateException and lazily recreate the client if closed.
Example fix
// before client.close(); client.request(requestOptions); // IllegalStateException // after client.close(); HttpClient client = vertx.createHttpClient(options); client.request(requestOptions);
Defensive patterns
Strategy: try-catch
Validate before calling
if (client.closeFuture().isComplete()) {
client = vertx.createHttpClient(options);
} Try / catch
try {
request = client.request(opts);
} catch (IllegalStateException e) {
client = vertx.createHttpClient(options);
request = client.request(opts);
} Prevention
- Own the client lifecycle in one place; stop producers before close().
- Wrap the client in a supplier/holder that recreates it when closed.
- Don't cache HttpClient instances beyond their owner's lifecycle.
When it happens
Trigger: Calling client.request(...) / websocket(...) / any operation after client.close() (or after the closeFuture completed); keeping a cached client instance used by a shutdown handler; closing the client in one callback while another request is still being initiated.
Common situations: Application shutdown racing with in-flight request creation; singleton client closed in a @PreDestroy/stop hook while a scheduler still fires requests; reusing a client obtained from a builder whose close future was resolved.
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/658f5690d27d30e7.
Report an issue: GitHub.