{"record":{"id":"5b04210ba4063789","repo":"quarkusio/quarkus","slug":"multiple-interface-io-quarkus-oidc-runtime-tokenin","errorCode":null,"errorMessage":"Multiple interface io.quarkus.oidc.runtime.TokenIntrospectionCache beans registered","messagePattern":"Multiple interface io\\.quarkus\\.oidc\\.runtime\\.TokenIntrospectionCache beans registered","errorType":"console","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java","lineNumber":104,"sourceCode":"        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) {\n        return getDynamicTenantConfig(context)\n                .flatMap(new Function<OidcTenantConfig, Uni<? extends OidcTenantConfig>>() {\n                    @Override","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java#L86-L122","documentation":"verifyResolvers() throws when the container finds multiple TokenIntrospectionCache beans. OIDC expects exactly one cache used to store introspected access-token results; ambiguity is detected eagerly at startup to prevent unpredictable caching.","triggerScenarios":"Two beans implementing io.quarkus.oidc.runtime.TokenIntrospectionCache are in the deployment, making the injected Instance ambiguous during @PostConstruct of DefaultTenantConfigResolver.","commonSituations":"Providing a custom TokenIntrospectionCache (e.g. Redis-backed) while another is registered; duplicate dependency bringing a second cache implementation; leaving both an old and a new cache class annotated.","solutions":["Keep exactly one TokenIntrospectionCache bean; remove or un-annotate (e.g. @Vetoed / remove scope annotation) the other.","Mark the intended implementation @Alternative with a higher @Priority so it unambiguously wins.","Use quarkus.oidc.token-introspection-cache.* config to tune the built-in cache rather than adding a second one."],"exampleFix":"// before\n@ApplicationScoped class Cache1 implements TokenIntrospectionCache { ... }\n@ApplicationScoped class Cache2 implements TokenIntrospectionCache { ... }\n\n// after\n@ApplicationScoped @Alternative @Priority(1)\nclass Cache2 implements TokenIntrospectionCache { ... }\n// Cache1 no longer a bean (removed or @Vetoed)","handlingStrategy":"validation","validationCode":"if (CDI.current().select(TokenIntrospectionCache.class).stream().count() > 1) {\n    throw new IllegalStateException(\"Only one TokenIntrospectionCache may be registered\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a single cache implementation; make it @Alternative when replacing the default","Use quarkus.oidc.token-introspection-cache.* properties to configure instead of new beans","Review shared internal libraries for duplicate SPI implementations"],"tags":["cdi","oidc","startup","cache"],"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"}