quarkusio/quarkus · error · org.jose4j.jwt.MalformedClaimException
expected claim %s must be a list of strings
Error message
expected claim %s must be a list of strings
What it means
Thrown by OidcProvider's CustomClaimsValidator when a required claim configured in quarkus.oidc.token.required-claims is expected to be a single string value in the token, but the app configured MULTIPLE required values for that claim (a set), and the token claim is a plain string. A string claim can only be compared against exactly one expected value, so the configuration is contradictory and MalformedClaimException is thrown.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java:746
}
}
return null;
}
private static String validate(String requiredClaimName, Set<String> requiredClaimValues, JwtClaims claims)
throws MalformedClaimException {
if (!claims.hasClaim(requiredClaimName)) {
return "claim " + requiredClaimName + " is missing";
}
if (claims.isClaimValueString(requiredClaimName)) {
if (requiredClaimValues.size() == 1) {
String actualClaimValue = claims.getStringClaimValue(requiredClaimName);
String requiredClaimValue = requiredClaimValues.iterator().next();
if (!requiredClaimValue.equals(actualClaimValue)) {
return "claim " + requiredClaimName + " does not match expected value of " + requiredClaimValues;
}
} else {
throw new MalformedClaimException("expected claim " + requiredClaimName + " must be a list of strings");
}
} else {
if (claims.isClaimValueStringList(requiredClaimName)) {
List<String> actualClaimValues = claims.getStringListClaimValue(requiredClaimName);
for (String requiredClaimValue : requiredClaimValues) {
if (!actualClaimValues.contains(requiredClaimValue)) {
return "claim " + requiredClaimName + " does not match expected value of " + requiredClaimValues;
}
}
} else {
throw new MalformedClaimException(
"expected claim " + requiredClaimName + " must be a list of strings or a string");
}
}
return null;
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Configure only ONE required value per claim if the token emits it as a plain string
- If multiple alternatives are needed, the token claim must be a JSON array of strings — ask the issuer to emit e.g. "acr": ["loa2","loa3"]
- Match exactly the value the token actually carries (decode the token to inspect the claim type)
- Use a custom Validator bean instead of static config if flexible matching is required
Example fix
# before (token acr is a plain string "loa2") quarkus.oidc.token.required-claims.acr=loa2,loa3 # after quarkus.oidc.token.required-claims.acr=loa2
Defensive patterns
Strategy: validation
Validate before calling
// decode the token and check the claim type before configuring multiple expected values
var claims = decodeJwtClaims(token);
Object acr = claims.get("acr");
if (!(acr instanceof List)) {
// claim is a plain string: configure exactly ONE required value
} Type guard
boolean isStringOrStringList(Object v) {
return v instanceof String || (v instanceof List<?> l && l.stream().allMatch(String.class::isInstance));
} Prevention
- Decode a real token to see the claim's JSON type before writing required-claims config
- Use a single required value for string claims; arrays only for list claims
- Prefer a custom Validator bean for OR-style matching
When it happens
Trigger: quarkus.oidc.token.required-claims.<name> maps to a set with 2+ values (e.g. comma-separated list) while the verified token's claim with that name is a single string, not a JSON array of strings.
Common situations: Developers write required-claims.acr=loa2,loa3 expecting OR-matching, but the provider emits acr as the string 'loa2' rather than an array; misunderstanding that multiple values only work when the token claim is a string list.
Related errors
- expected claim %s must be a list of strings or a string
- Unrecognized dependency flag '<trimmed>'. Supported flags: O
- Parameter 'mode' was set to '<mode>' while expected one of '
- Parameter 'mode' was set to '<mode>' while expected one of '
- Parameter 'mode' was set to '<mode>' while expected one of '
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/2395ef5fb5461d98.
Report an issue: GitHub.