quarkusio/quarkus · critical · IllegalStateException
Multiple interface io.quarkus.oidc.runtime.TokenIntrospectio
Error message
Multiple interface io.quarkus.oidc.runtime.TokenIntrospectionCache beans registered
What it means
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.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java:104
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) {
return getDynamicTenantConfig(context)
.flatMap(new Function<OidcTenantConfig, Uni<? extends OidcTenantConfig>>() {
@OverrideView on GitHub (pinned to e1c734241f)
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.
Example fix
// before
@ApplicationScoped class Cache1 implements TokenIntrospectionCache { ... }
@ApplicationScoped class Cache2 implements TokenIntrospectionCache { ... }
// after
@ApplicationScoped @Alternative @Priority(1)
class Cache2 implements TokenIntrospectionCache { ... }
// Cache1 no longer a bean (removed or @Vetoed) Defensive patterns
Strategy: validation
Validate before calling
if (CDI.current().select(TokenIntrospectionCache.class).stream().count() > 1) {
throw new IllegalStateException("Only one TokenIntrospectionCache may be registered");
} Prevention
- 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
When it happens
Trigger: Two beans implementing io.quarkus.oidc.runtime.TokenIntrospectionCache are in the deployment, making the injected Instance ambiguous during @PostConstruct of DefaultTenantConfigResolver.
Common situations: 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.
Related errors
- Multiple interface io.quarkus.oidc.TenantConfigResolver bean
- Multiple interface io.quarkus.oidc.runtime.TokenStateManager
- Multiple interface io.quarkus.oidc.UserInfo beans registered
- Multiple interface io.quarkus.oidc.JavaScriptRequestChecker
- Failed to find any non-blocking provider for startup actions
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5b04210ba4063789.
Report an issue: GitHub.