eclipse-vertx/vert.x · error · IllegalStateException
Resource manager closed
Error message
Resource manager closed
What it means
ResourceManager.checkStatus() throws this IllegalStateException when the manager status is 2, i.e. close() has fully completed. After close, all resources have been released and no new withResource() requests are accepted. It differs from 'shutdown' (status 1), which rejects new work but is a softer phase.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/internal/resource/ResourceManager.java:112
*
* @param key the resource key
* @return the future resolved with the resource
*/
public <T> Future<T> withResourceAsync(K key, Function<K, R> provider, BiFunction<R, Boolean, Future<T>> function) {
return withResource(key, provider, Function.identity(), (res, created) -> {
if (res.before()) {
return function.apply(res, created).andThen(ar -> res.after());
}
return null;
});
}
private void checkStatus() {
int st = status.get();
if (st == 1) {
throw new IllegalStateException("Resource manager shutdown");
} else if (st == 2) {
throw new IllegalStateException("Resource manager closed");
}
}
/**
* Shutdown the resource manager: any new request will be rejected.
*/
public void shutdown() {
if (status.compareAndSet(0, 1)) {
for (ManagedResource resource : resources.values()) {
resource.shutdown();
}
status.set(2);
}
}
/**
* Close the resource manager, all resource are closed forcibly.
*/View on GitHub (pinned to fb308bd8c3)
Solutions
- Stop all consumers before calling close(); cancel schedulers and complete in-flight work first
- Create a fresh Vertx/client/manager instance instead of using the closed one
- Clear cached references to closed managers so stale code paths cannot reach them
- Catch IllegalStateException and treat it as a terminal lifecycle signal — reinitialize or fail the caller deliberately
Example fix
// before
private static final Vertx VERTX = Vertx.vertx(); // closed elsewhere, reused later -> Resource manager closed
// after
private volatile Vertx vertx;
Vertx v = vertx;
if (v == null) { v = Vertx.vertx(); vertx = v; } Defensive patterns
Strategy: try-catch
Validate before calling
// keep a closed flag around the manager holder
if (managerClosed.get()) {
return Future.failedFuture(new IllegalStateException("manager already closed"));
}
return manager.withResource(key, supplier); Type guard
boolean usable(ResourceManager m) { return m != null && !m.isClosed(); } // track close via your own flag or wrapper Try / catch
try {
return manager.withResource(key, supplier);
} catch (IllegalStateException e) {
if ("Resource manager closed".equals(e.getMessage())) {
manager = recreate(); // or fail terminally — never retry on the closed instance
return manager.withResource(key, supplier);
}
throw e;
} Prevention
- Clear cached/static references to a manager as soon as close() completes
- Close the owning Vertx/client only after all consumers are stopped
- Treat this error as terminal: recreate the instance instead of retrying on the closed one
- Use lifecycle frameworks (DI close hooks) to enforce close ordering across components
When it happens
Trigger: Calling withResource (or any resource-acquiring API) after ResourceManager.close() finished — typically using a Vertx instance, client, or connection provider after its close() completed, or a stale reference to a manager captured before close.
Common situations: Reusing a closed Vertx/client from a static or cached field; scheduled/periodic tasks firing after the owning instance was closed; double-close bugs where a second component still holds the old manager.
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/ba5fbcdc38bd8e99.
Report an issue: GitHub.