quarkusio/quarkus · error · java.lang.IllegalStateException
Multiple io.quarkus.oidc.TenantResolver beans registered
Error message
Multiple io.quarkus.oidc.TenantResolver beans registered
What it means
StaticTenantResolver's constructor throws IllegalStateException when the CDI instance of io.quarkus.oidc.TenantResolver is ambiguous, i.e. more than one custom TenantResolver bean is registered. Quarkus supports at most one custom tenant resolver; multiple beans make tenant selection non-deterministic.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/StaticTenantResolver.java:47
final class StaticTenantResolver {
private static final Logger LOG = Logger.getLogger(StaticTenantResolver.class);
private final TenantResolver[] staticTenantResolversGroup1;
private final IssuerBasedTenantResolver issuerBasedTenantResolver;
private final TenantResolver[] staticTenantResolversGroup2;
StaticTenantResolver(TenantConfigBean tenantConfigBean, String rootPath, boolean resolveTenantsWithIssuer,
Instance<TenantResolver> tenantResolverInstance) {
List<TenantResolver> staticTenantResolvers = new ArrayList<>();
// STATIC TENANT RESOLVERS BY PRIORITY:
// 0. annotation based resolver
// 1. custom tenant resolver
if (tenantResolverInstance.isResolvable()) {
if (tenantResolverInstance.isAmbiguous()) {
throw new IllegalStateException("Multiple " + TenantResolver.class + " beans registered");
}
staticTenantResolvers.add(tenantResolverInstance.get());
}
// 2. path-matching tenant resolver
var pathMatchingTenantResolver = PathMatchingTenantResolver.of(tenantConfigBean.getStaticTenantsConfig(), rootPath,
tenantConfigBean.getDefaultTenant());
if (pathMatchingTenantResolver != null) {
staticTenantResolvers.add(pathMatchingTenantResolver);
}
this.staticTenantResolversGroup1 = staticTenantResolvers.toArray(new TenantResolver[0]);
// 3. issuer-based tenant resolver
if (resolveTenantsWithIssuer) {
this.issuerBasedTenantResolver = IssuerBasedTenantResolver.of(
tenantConfigBean.getStaticTenantsConfig(), tenantConfigBean.getDefaultTenant());
} else {View on GitHub (pinned to e1c734241f)
Solutions
- Remove one of the duplicate TenantResolver bean implementations
- Make only one resolver active using @Alternative with @Priority, or @IfBuildProfile/@LookupIfProperty conditions
- Merge the resolution logic of both resolvers into a single TenantResolver
Example fix
// before: two @ApplicationScoped TenantResolver beans
// after: single bean merging logic, or disable one
@ApplicationScoped
@LookupIfProperty(name = "tenant.resolver.v2.enabled", stringValue = "true")
public class V2TenantResolver implements TenantResolver { ... } Defensive patterns
Strategy: validation
Validate before calling
Instance<TenantResolver> resolvers = cdi.select(TenantResolver.class);
if (resolvers.stream().count() > 1) throw new IllegalStateException("Register only one TenantResolver bean"); Try / catch
try { buildResolver(); } catch (IllegalStateException e) { log.error("Multiple TenantResolver beans: keep one (use @Alternative/@Priority for the active one)", e); } Prevention
- Search the classpath for TenantResolver implementations before adding a new one
- Gate resolvers with @LookupIfProperty/@IfBuildProfile so only one activates
- Merge multi-tenant routing logic into a single resolver
When it happens
Trigger: Application (or a library) registers two or more beans implementing io.quarkus.oidc.TenantResolver; the OIDC runtime builds StaticTenantResolver during tenant resolution, sees tenantResolverInstance.isAmbiguous(), and throws.
Common situations: Adding a second TenantResolver (e.g. a library dependency already provides one); copy-pasting a resolver class in a multi-module app; forgetting @Alternative/@Priority exclusions leading to duplicate beans.
Related errors
- %s type can not be used to represent JWT claims in @Singleto
- 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
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/20386edcb4e675a6.
Report an issue: GitHub.