quarkusio/quarkus · error · IllegalStateException

OidcClient %s is closed

Error message

OidcClient %s is closed

What it means

OidcClientImpl.checkClosed throws IllegalStateException when any token operation (getTokens, refreshTokens, revokeAccessToken) is invoked after close() was called on the client. Once closed, the underlying HTTP client is shut down and the instance must not be reused.

Source

Thrown at extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java:473

        MultiMap newMap = MultiMap.caseInsensitiveMultiMap();
        newMap.addAll(oldMap);
        return newMap;
    }

    @Override
    public void close() throws IOException {
        if (!closed) {
            client.close();
            if (clientAssertionProvider != null) {
                clientAssertionProvider.close();
            }
            closed = true;
        }
    }

    private void checkClosed() {
        if (closed) {
            throw new IllegalStateException("OidcClient " + oidcConfig.id().get() + " is closed");
        }
    }

    private Uni<HttpRequest<Buffer>> filterHttpRequest(
            OidcRequestContextProperties requestProps,
            OidcEndpoint.Type endpointType, HttpRequest<Buffer> request, Buffer body) {
        return OidcCommonUtils.filterHttpRequest(requestProps, request, body, requestFilters, endpointType);
    }

    private Uni<AsyncCredentials> withAsyncCredentials() {
        if (clientAssertionProvider != null) {
            return clientAssertionProvider.getClientAssertion().map(AsyncCredentials::new);
        }
        return AsyncCredentials.UNI_WITH_EMPTY_CREDENTIALS;
    }

    OidcClientConfig getConfig() {
        return oidcConfig;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Stop using the closed client; obtain a fresh instance from OidcClients or OidcClientProvider
  2. Remove explicit close() calls unless the client lifecycle is fully owned by your code
  3. Check isClosed() / guard usage in long-lived components holding client references
  4. If lifecycle is managed by Quarkus (injected OidcClient), avoid closing it manually

Example fix

// before
oidcClient.close();
// ... later ...
Tokens t = oidcClient.getTokens().await().indefinitely(); // IllegalStateException

// after
if (!oidcClient.isClosed()) {
    Tokens t = oidcClient.getTokens().await().indefinitely();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (client.isClosed()) { client = recreateClient(); }

Try / catch

try { return client.getTokens().await().indefinitely(); } catch (IllegalStateException e) { if (e.getMessage() != null && e.getMessage().endsWith("is closed")) { client = oidcClients.newClient(config).await().indefinitely(); return client.getTokens().await().indefinitely(); } throw e; }

Prevention

When it happens

Trigger: Calling getTokens(), awaitTokens(), refreshTokens(), or revokeAccessToken() on an OidcClient instance after close() — e.g. holding a stale reference after application shutdown, or reusing a client created in a scope that already closed it.

Common situations: Application shutdown hooks or request-scoped code calling close() then later code still using the injected/stored client; custom client management via OidcClientsImpl.newClient with manual lifecycle; hot redeployment scenarios where old references persist.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/26322e4a8d2ff5e3. Report an issue: GitHub.