hs-web/hsweb-framework · error · IllegalStateException

Recycler is closed

Error message

Recycler is closed

What it means

IllegalStateException raised from RecyclerImpl.initialValue (the ThreadLocal initialization hook) when the recycler's closed flag has been set. It fires when a thread first tries to obtain a pooled object via get()/withRecycled after the Recycler was closed; since closed recyclers destroy all pooled resources, no new instance can be created, so any late acquisition of a resource from this recycler fails fast with this error.

Solutions

  1. Stop using the recycler and drain/release all borrowed objects before closing
  2. Guard usage with Recycler's closed/alive check before take/doWith
  3. Create a new Recycler instance after closing the old one
  4. Fix lifecycle ordering so close() runs only after all tasks complete

Example fix

// before
recycler.close();
Recyclable<T> r = recycler.take(true);
// after
recycler.close();
Recyclable<T> r = recycler.isClosed() ? null : recycler.take(true);
Defensive patterns

Strategy: fallback

Validate before calling

if (recycler.isClosed()) { /* allocate directly */ }

Type guard

boolean usable = recycler != null && !recycler.isClosed();

Try / catch

try {
    return recycler.take(sync);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Recycler is closed")) return fallbackAlloc();
    throw e;
}

Prevention

When it happens

Trigger: A thread first accesses the ThreadLocal pool (via take/doWith/get) after RecyclerImpl.close()/shutdown was called; the lazy ThreadLocal map then tries initialValue().

Common situations: Objects obtained earlier still used by worker threads after application shutdown or recycler close; closing the recycler while reactive operators still borrow pooled objects.

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 hs-web/hsweb-framework@b2cfc85a57 (2026-09-13). Data as JSON: /api/errors/39e4656fd58b753c. Report an issue: GitHub.

Appendix: source

Thrown at hsweb-core/src/main/java/org/hswebframework/web/recycler/RecyclerImpl.java:60

        }
        if (rest == null) {
            throw new IllegalArgumentException("rest cannot be null");
        }
        if (destroy == null) {
            throw new IllegalArgumentException("destroy cannot be null");
        }

        this.factory = factory;
        this.rest = rest;
        this.destroy = destroy;
        this.managedResource = managedResource;
        this.queue = new MpmcArrayQueue<>(size);
    }

    @Override
    protected ThreadLocalRecyclable<T> initialValue() throws Exception {
        if (closed.get()) {
            throw new IllegalStateException("Recycler is closed");
        }
        return new ThreadLocalRecyclable<T>(this, factory.get(), null);
    }

    @Override
    protected void onRemoval(ThreadLocalRecyclable<T> value) {
        resetAndDestroy(value.value);
    }

    private boolean doReset(T val) {
        try {
            rest.accept(val);
            return true;
        } catch (Throwable e) {
            log.warn("reset object [{}] failed", val, e);
            return false;
        }
    }

View on GitHub (pinned to b2cfc85a57)