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

  1. Stop all consumers before calling close(); cancel schedulers and complete in-flight work first
  2. Create a fresh Vertx/client/manager instance instead of using the closed one
  3. Clear cached references to closed managers so stale code paths cannot reach them
  4. 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

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.