quarkusio/quarkus · error · io.quarkus.oidc.runtime.OIDCException

OIDC tenants '%s' and '%s' share the same resource metadata

Error message

OIDC tenants '%s' and '%s' share the same resource metadata path '%s', which is not supported

What it means

ResourceMetadataHandler.createOrUpdatePathMatcher throws OIDCException when two different OIDC tenants resolve to the same resource metadata path. Each tenant must have a unique resource metadata route; a collision makes routing ambiguous, so startup/update fails with this error (logged and rethrown).

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/ResourceMetadataHandler.java:91

                }
                String routePath = getResourceMetadataPath(configContext.oidcConfig(), resolver.getRootPath());
                if (routePath.contains("*")) {
                    throw new IllegalStateException("Resource metadata path cannot contain a wildcard '*' character");
                }
                OidcTenantConfig previousConfig = pathCache.put(routePath, configContext.oidcConfig());
                if (previousConfig == null) {
                    Handler<RoutingContext> routeHandler = new RouteHandler(configContext.oidcConfig(), resolver);
                    builder.addPath(routePath, routeHandler);
                } else {
                    String previousTenantId = previousConfig.tenantId().get();
                    String currentTenantId = configContext.oidcConfig().tenantId().get();
                    // maybe invalid state, but technically it could happen that some produces a static tenant with
                    // a same id as a dynamic tenant
                    if (!previousTenantId.equals(currentTenantId)) {
                        String errorMessage = "OIDC tenants '%s' and '%s' share the same resource metadata path '%s', which is not supported"
                                .formatted(previousTenantId, currentTenantId, routePath);
                        LOG.error(errorMessage);
                        throw new OIDCException(errorMessage);
                    }
                }
            }
        }
        if (builder != null) {
            pathMatcher = builder.build();
        } else {
            pathMatcher = null;
        }
    }

    static String getResourceMetadataPath(OidcTenantConfig oidcConfig, String configuredRootPath) {
        String configuredResource = oidcConfig.resourceMetadata().resource().orElse("");

        String relativePath = null;

        if (configuredResource.startsWith(HTTP_SCHEME)) {
            relativePath = URI.create(configuredResource).getRawPath();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Give each tenant a unique resource metadata base path in its OidcTenantConfig
  2. Fix the tenant id duplication/collision by renaming one of the tenants
  3. Review TenantResolver-generated dynamic tenant configs so paths do not overlap static tenant paths

Example fix

// before
quarkus.oidc.tenant-a.resource-metadata.base-path=/api
quarkus.oidc.tenant-b.resource-metadata.base-path=/api
// after
quarkus.oidc.tenant-a.resource-metadata.base-path=/api/tenant-a
quarkus.oidc.tenant-b.resource-metadata.base-path=/api/tenant-b
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
for (OidcTenantConfig t : tenants) {
    if (!seen.add(resourceMetadataPath(t))) throw new IllegalArgumentException("Duplicate resource metadata path across tenants");
}

Try / catch

try { startApplication(); } catch (OIDCException e) { log.error("Two tenants share a resource metadata path: give each a unique base path", e); }

Prevention

When it happens

Trigger: During setup or updatePathMatcher, pathCache.put returns a previous config for the same routePath whose tenant id differs from the current one; e.g. two tenants (static or dynamic) configured with the same base path for resource metadata.

Common situations: Two tenants with identical or overlapping resource-metadata base paths; dynamic tenants created at runtime colliding with a static tenant's path; copy-paste config where the second tenant was not given a distinct base path.

Related errors


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