quarkusio/quarkus · error · IllegalStateException
An exception should have been thrown because authentication
Error message
An exception should have been thrown because authentication happened before Tenant was selected with the @Tenant annotation
What it means
This IllegalStateException is thrown by the TenantEchoResource endpoint /http-security-policy-applies-all-diff as a canary: when a @Tenant annotation is combined with an HTTP SecurityPolicy that applies to all paths, authentication must never happen before the tenant is selected. Reaching this method body proves the ordering guarantee was violated, so the endpoint always fails loudly.
Source
Thrown at integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/TenantEchoResource.java:60
@Path("/hr-classic-and-jaxrs-perm-check")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getHrTenantClassicAndJaxRsPermCheck() {
return getTenantInternal();
}
@PermissionsAllowed("get-tenant")
@Path("/hr-identity-augmentation")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getHrTenantIdentityAugmentation() {
return getTenantInternal();
}
@Path("/http-security-policy-applies-all-diff")
@GET
public String httpSecurityPolicyAppliesAllDiff() {
throw new IllegalStateException("An exception should have been thrown because authentication happened" +
" before Tenant was selected with the @Tenant annotation");
}
@Path("/http-security-policy-applies-all-same")
@GET
public String httpSecurityPolicyAppliesAllSame() {
return getTenantInternal();
}
private String getTenantInternal() {
return OidcUtils.TENANT_ID_ATTRIBUTE + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE)
+ ", static.tenant.id=" + routingContext.get("static.tenant.id")
+ ", name=" + identity.getPrincipal().getName()
+ ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "="
+ routingContext.get(OidcUtils.TENANT_ID_SET_BY_ANNOTATION);
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Verify the HTTP SecurityPolicy is registered so it does not force authentication before tenant selection for @Tenant-annotated endpoints.
- Check that the @Tenant interceptor runs prior to authentication in this configuration.
- Review recent changes to HTTP SecurityPolicy appliesTo=ALL handling in the Quarkus version under test.
- Enable DEBUG logging for io.quarkus.vertx.http.runtime.security and io.quarkus.oidc to inspect ordering.
Example fix
// before (broken ordering — endpoint reached after authentication)
@Path("/http-security-policy-applies-all-diff")
@GET
public String httpSecurityPolicyAppliesAllDiff() {
throw new IllegalStateException("authentication happened before @Tenant was selected");
}
// after (correct ordering: tenant selected before auth; method returns normally)
@Path("/http-security-policy-applies-all-diff")
@GET
@Tenant("diff")
public String httpSecurityPolicyAppliesAllDiff() {
return getTenantInternal();
} Defensive patterns
Strategy: type-guard
Validate before calling
// in a test, assert the endpoint is never reachable with an authenticated identity
RestAssured.get("/http-security-policy-applies-all-diff")
.then().statusCode(500); // must not return 200 Type guard
boolean tenantSelectedBeforeAuth(SecurityIdentity identity, Tenant currentTenant) {
return currentTenant != null && identity != null && identity.isAnonymous() == false
&& TENANT_AUTH_ORDER.isTenantFirst(); // custom ordering check
} Try / catch
try {
tenantEchoResource.httpSecurityPolicyAppliesAllDiff();
} catch (IllegalStateException e) {
assertTrue(e.getMessage().contains("before Tenant was selected"));
} Prevention
- Keep @Tenant-annotated endpoints out of HTTP SecurityPolicies that force appliesTo=all authentication.
- Add ordering regression tests whenever upgrading Quarkus HTTP security versions.
- Document policy-vs-tenant interceptor ordering for custom policies.
- Verify with DEBUG logs on io.quarkus.vertx.http.runtime.security that tenant resolution precedes authentication.
When it happens
Trigger: GET /http-security-policy-applies-all-diff is dispatched and Quarkus HTTP security policy authentication runs before the @Tenant annotation-based tenant selection resolves the tenant — i.e. a regression in security-policy vs tenant-interceptor ordering.
Common situations: Upgrading Quarkus versions where HTTP SecurityPolicy execution order changed, adding a policy with appliesTo=all while using @Tenant on the same endpoint, or misconfigured policy registration in the application.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to find a matching OidcTenantConfig for tenant:
- OidcProviderClient can not be injected
- Invalid tenant id
- /tenant-absolute-redirect/callback is a callback method
- Tenant id must have been set by either the session or state
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/47a58a2330ea928a.
Report an issue: GitHub.