quarkusio/quarkus · critical · IllegalStateException
Multiple interface io.quarkus.oidc.JavaScriptRequestChecker
Error message
Multiple interface io.quarkus.oidc.JavaScriptRequestChecker beans registered
What it means
verifyResolvers() throws when multiple JavaScriptRequestChecker beans are registered. This OIDC SPI decides whether an incoming request should be treated as a JavaScript/browser request for auth-code-flow purposes, so exactly one implementation must be resolvable.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java:110
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>>() {
@Override
public Uni<OidcTenantConfig> apply(OidcTenantConfig oidcTenantConfig) {
if (oidcTenantConfig != null) {
return Uni.createFrom().item(oidcTenantConfig);
}
final String tenantId = context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
View on GitHub (pinned to e1c734241f)
Solutions
- Keep a single JavaScriptRequestChecker implementation; delete or un-annotate the extra one.
- Use @Alternative plus @Priority on the intended implementation.
- Alternatively rely on quarkus.oidc authentication.js-request-checker-style config or set AuthenticationScheme headers instead of multiple checkers.
Example fix
// before
@ApplicationScoped class CheckerA implements JavaScriptRequestChecker { ... }
@ApplicationScoped class CheckerB implements JavaScriptRequestChecker { ... }
// after - only CheckerB active
@ApplicationScoped @Alternative @Priority(1)
class CheckerB implements JavaScriptRequestChecker { ... } Defensive patterns
Strategy: validation
Validate before calling
long checkers = CDI.current().select(JavaScriptRequestChecker.class).stream().count();
if (checkers > 1) {
throw new IllegalStateException("Register only one JavaScriptRequestChecker");
} Prevention
- Keep exactly one SPA request checker; mark extras @Alternative
- Use quarkus.oidc tenancy/auth config for browser detection when possible
- Check internal libraries before introducing another checker
When it happens
Trigger: Two beans implementing io.quarkus.oidc.JavaScriptRequestChecker exist in the container, making javaScriptRequestChecker.isAmbiguous() true during DefaultTenantConfigResolver startup verification.
Common situations: Adding a custom checker for SPAs while another (e.g. from a shared internal library) is present; duplicate classes in different packages both annotated @ApplicationScoped.
Related errors
- Multiple interface io.quarkus.oidc.TenantConfigResolver bean
- Multiple interface io.quarkus.oidc.runtime.TokenStateManager
- Multiple interface io.quarkus.oidc.runtime.TokenIntrospectio
- Multiple interface io.quarkus.oidc.UserInfo beans registered
- 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/3f79fa9eb2c1a1b7.
Report an issue: GitHub.