quarkusio/quarkus · critical · IllegalStateException

Multiple interface io.quarkus.oidc.runtime.TokenStateManager

Error message

Multiple interface io.quarkus.oidc.runtime.TokenStateManager beans registered

What it means

verifyResolvers() in DefaultTenantConfigResolver fails startup when more than one TokenStateManager bean is registered. Quarkus OIDC injects a single TokenStateManager to persist tokens (in cookies/session) and cannot disambiguate between multiple implementations.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java:101

            @ConfigProperty(name = "quarkus.security.events.enabled") boolean securityEventsEnabled,
            @ConfigProperty(name = "quarkus.http.root-path") String rootPath, TenantConfigBean tenantConfigBean) {
        this.blockingRequestContext = new BlockingTaskRunner<OidcTenantConfig>(blockingExecutor);
        this.securityEventObserved = SecurityEventHelper.isEventObserved(new SecurityEvent(null, (SecurityIdentity) null),
                beanManager, securityEventsEnabled);
        this.tenantConfigBean = tenantConfigBean;
        this.annotationBasedTenantResolutionEnabled = Boolean.getBoolean(OidcUtils.ANNOTATION_BASED_TENANT_RESOLUTION_ENABLED);
        this.rootPath = rootPath;
        this.staticTenantResolver = new StaticTenantResolver(tenantConfigBean, rootPath, resolveTenantsWithIssuer,
                tenantResolverInstance);
    }

    @PostConstruct
    public void verifyResolvers() {
        if (tenantConfigResolver.isResolvable() && tenantConfigResolver.isAmbiguous()) {
            throw new IllegalStateException("Multiple " + TenantConfigResolver.class + " beans registered");
        }
        if (tokenStateManager.isAmbiguous()) {
            throw new IllegalStateException("Multiple " + TokenStateManager.class + " beans registered");
        }
        if (tokenIntrospectionCache.isAmbiguous()) {
            throw new IllegalStateException("Multiple " + TokenIntrospectionCache.class + " beans registered");
        }
        if (userInfoCache.isAmbiguous()) {
            throw new IllegalStateException("Multiple " + UserInfo.class + " beans registered");
        }
        if (javaScriptRequestChecker.isAmbiguous()) {
            throw new IllegalStateException("Multiple " + JavaScriptRequestChecker.class + " beans registered");
        }

    }

    List<AuthenticationCompletionAction> authenticationCompletionActions() {
        return authenticationCompletionActions;
    }

    Uni<OidcTenantConfig> resolveConfig(RoutingContext context) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove the duplicate TokenStateManager implementation.
  2. Annotate your custom implementation with @Alternative and @Priority(1) (and register it via quarkus.arc.exclude or @LookupProperties if needed) so only it is used.
  3. If customization is needed without replacing the bean, prefer quarkus.oidc.token-state-manager.* config options (split-tokens, encryption-required) instead of a second bean.

Example fix

// before
@ApplicationScoped
class MyTokenStateManager implements TokenStateManager { ... }
// default manager also active => ambiguous

// after
@ApplicationScoped
@Alternative
@Priority(1)
class MyTokenStateManager implements TokenStateManager { ... }
Defensive patterns

Strategy: validation

Validate before calling

long managers = CDI.current().select(TokenStateManager.class).stream().count();
if (managers > 1) {
    throw new IllegalStateException("Multiple TokenStateManager beans: " + managers);
}

Prevention

When it happens

Trigger: Register two beans implementing io.quarkus.oidc.runtime.TokenStateManager (custom @Alternative-less duplicates) so the injected Instance tokenStateManager.isAmbiguous() returns true at @PostConstruct time.

Common situations: Writing a custom TokenStateManager while the default one is also active (e.g. the custom bean lacks @Alternative); adding a library dependency that ships its own TokenStateManager; refactoring that leaves an old implementation annotated as a bean.

Related errors


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