jwtk/jjwt · error · IncorrectClaimException
Expected <expectedClaimName> claim to be: <expectedClaimValu
Error message
Expected <expectedClaimName> claim to be: <expectedClaimValue>, but was: <actualClaimValue>.
What it means
Thrown as IncorrectClaimException when a required claim's value does not exactly equal the expected value passed to require(claimName, expectedValue) for a scalar (non-Collection, non-Date) expected value. This is the equality-failure branch of JJWT's claim requirement validation, after the missing-claim and collection-membership checks.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:771
} else {
msg += ": " + expectedClaimValue;
}
throw new MissingClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);
} else if (expectedClaimValue instanceof Collection) {
Collection<?> expectedValues = (Collection<?>) expectedClaimValue;
Collection<?> actualValues = actualClaimValue instanceof Collection ? (Collection<?>) actualClaimValue :
Collections.setOf(actualClaimValue);
for (Object expectedValue : expectedValues) {
if (!Collections.contains(actualValues.iterator(), expectedValue)) {
String msg = String.format(MISSING_EXPECTED_CLAIM_VALUE_MESSAGE_TEMPLATE,
expectedValue, expectedClaimName, actualValues);
throw new IncorrectClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);
}
}
} else if (!expectedClaimValue.equals(actualClaimValue)) {
String msg = String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
expectedClaimName, expectedClaimValue, actualClaimValue);
throw new IncorrectClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);
}
}
}
@SuppressWarnings("deprecation")
@Override
public <T> T parse(CharSequence compact, JwtHandler<T> handler) {
return parse(compact, Payload.EMPTY).accept(handler);
}
private Jwt<?, ?> parse(CharSequence compact, Payload unencodedPayload) {
Assert.hasText(compact, "JWT String argument cannot be null or empty.");
return parse(new CharSequenceReader(compact), unencodedPayload);
}
@Override
public Jwt<Header, byte[]> parseContentJwt(CharSequence jwt) {
return parse(jwt).accept(Jwt.UNSECURED_CONTENT);View on GitHub (pinned to fb71496164)
Solutions
- Verify the exact expected value against the token payload (decode the claims section) and fix require(...).
- Fix the issuer to emit the expected claim value.
- Normalize issuer/audience strings on both sides (trailing slashes, case) and re-deploy.
- If multiple acceptable values exist, use require(name, collectionOfAcceptedValues) instead of a scalar.
Example fix
// before
Jwts.parser().require("iss", "https://auth.example.com/").verifyWith(key).build().parse(jwt); // token iss="https://auth.example.com"
// after
Jwts.parser().require("iss", "https://auth.example.com").verifyWith(key).build().parse(jwt); Defensive patterns
Strategy: validation
Validate before calling
io.jsonwebtoken.Claims c = Jwts.parser().build().parseUnsecuredClaims(jwt).getPayload();
if (!"https://auth.example.com".equals(c.get("iss"))) {
throw new IllegalStateException("Unexpected iss: " + c.get("iss"));
} Try / catch
try {
claims = Jwts.parser().requireIssuer("https://auth.example.com").verifyWith(key)
.build().parseSignedClaims(jwt).getPayload();
} catch (io.jsonwebtoken.IncorrectClaimException e) {
// reject: claim value mismatch; log e.getClaimName() and expected/actual
} Prevention
- Normalize issuer URLs (no trailing slash, consistent scheme) on both sides
- Use requireIssuer/requireSubject helpers rather than raw string equality in app code
- Centralize expected claim values in configuration, not hardcoded literals
- Test with tokens from every legitimate issuer variant
When it happens
Trigger: parser.require("iss", "https://issuer.example.com") or require("sub", userId) where the claim is present but its value differs from the expected one (uses Object.equals).
Common situations: Wrong issuer URL or trailing-slash differences in 'iss'; token signed for a different subject/user; environment-specific issuer values (staging vs prod); case sensitivity mismatches ('APP' vs 'app').
Related errors
- JWT Claim '<expectedClaimName>' was expected to be a Date, b
- Missing '<expectedClaimName>' claim. Expected value: <expect
- Missing expected '<expectedValue>' value in '<expectedClaimN
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/958667ae46436a2f.
Report an issue: GitHub.