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

  1. Keep a single JavaScriptRequestChecker implementation; delete or un-annotate the extra one.
  2. Use @Alternative plus @Priority on the intended implementation.
  3. 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

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


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