{"record":{"id":"a810bf000e5f1396","repo":"quarkusio/quarkus","slug":"multiple-interface-io-quarkus-oidc-runtime-tokenst","errorCode":null,"errorMessage":"Multiple interface io.quarkus.oidc.runtime.TokenStateManager beans registered","messagePattern":"Multiple interface io\\.quarkus\\.oidc\\.runtime\\.TokenStateManager beans registered","errorType":"console","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java","lineNumber":101,"sourceCode":"            @ConfigProperty(name = \"quarkus.security.events.enabled\") boolean securityEventsEnabled,\n            @ConfigProperty(name = \"quarkus.http.root-path\") String rootPath, TenantConfigBean tenantConfigBean) {\n        this.blockingRequestContext = new BlockingTaskRunner<OidcTenantConfig>(blockingExecutor);\n        this.securityEventObserved = SecurityEventHelper.isEventObserved(new SecurityEvent(null, (SecurityIdentity) null),\n                beanManager, securityEventsEnabled);\n        this.tenantConfigBean = tenantConfigBean;\n        this.annotationBasedTenantResolutionEnabled = Boolean.getBoolean(OidcUtils.ANNOTATION_BASED_TENANT_RESOLUTION_ENABLED);\n        this.rootPath = rootPath;\n        this.staticTenantResolver = new StaticTenantResolver(tenantConfigBean, rootPath, resolveTenantsWithIssuer,\n                tenantResolverInstance);\n    }\n\n    @PostConstruct\n    public void verifyResolvers() {\n        if (tenantConfigResolver.isResolvable() && tenantConfigResolver.isAmbiguous()) {\n            throw new IllegalStateException(\"Multiple \" + TenantConfigResolver.class + \" beans registered\");\n        }\n        if (tokenStateManager.isAmbiguous()) {\n            throw new IllegalStateException(\"Multiple \" + TokenStateManager.class + \" beans registered\");\n        }\n        if (tokenIntrospectionCache.isAmbiguous()) {\n            throw new IllegalStateException(\"Multiple \" + TokenIntrospectionCache.class + \" beans registered\");\n        }\n        if (userInfoCache.isAmbiguous()) {\n            throw new IllegalStateException(\"Multiple \" + UserInfo.class + \" beans registered\");\n        }\n        if (javaScriptRequestChecker.isAmbiguous()) {\n            throw new IllegalStateException(\"Multiple \" + JavaScriptRequestChecker.class + \" beans registered\");\n        }\n\n    }\n\n    List<AuthenticationCompletionAction> authenticationCompletionActions() {\n        return authenticationCompletionActions;\n    }\n\n    Uni<OidcTenantConfig> resolveConfig(RoutingContext context) {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java#L83-L119","documentation":"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.","triggerScenarios":"Register two beans implementing io.quarkus.oidc.runtime.TokenStateManager (custom @Alternative-less duplicates) so the injected Instance tokenStateManager.isAmbiguous() returns true at @PostConstruct time.","commonSituations":"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.","solutions":["Remove the duplicate TokenStateManager implementation.","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.","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."],"exampleFix":"// before\n@ApplicationScoped\nclass MyTokenStateManager implements TokenStateManager { ... }\n// default manager also active => ambiguous\n\n// after\n@ApplicationScoped\n@Alternative\n@Priority(1)\nclass MyTokenStateManager implements TokenStateManager { ... }","handlingStrategy":"validation","validationCode":"long managers = CDI.current().select(TokenStateManager.class).stream().count();\nif (managers > 1) {\n    throw new IllegalStateException(\"Multiple TokenStateManager beans: \" + managers);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always annotate replacement SPI beans with @Alternative and @Priority","Tune quarkus.oidc.token-state-manager.* config instead of adding beans","Audit dependencies for libraries shipping OIDC SPI implementations","Add an ArC startup smoke test to catch ambiguity early"],"tags":["cdi","oidc","startup","token-state"],"backgroundTag":"ambiguous-cdi-bean","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}