{"record":{"id":"7f6c928d79c04ec6","repo":"jwtk/jjwt","slug":"missing-expected-expectedvalue-value-in-expe","errorCode":null,"errorMessage":"Missing expected '<expectedValue>' value in '<expectedClaimName>' claim <actualValues>.","messagePattern":"Missing expected '<expectedValue>' value in '<expectedClaimName>' claim <actualValues>\\.","errorType":"exception","errorClass":"IncorrectClaimException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":765,"sourceCode":"\n            if (actualClaimValue == null) {\n                boolean collection = expectedClaimValue instanceof Collection;\n                String msg = \"Missing '\" + expectedClaimName + \"' claim. Expected value\";\n                if (collection) {\n                    msg += \"s: \" + expectedClaimValue;\n                } else {\n                    msg += \": \" + expectedClaimValue;\n                }\n                throw new MissingClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);\n            } else if (expectedClaimValue instanceof Collection) {\n                Collection<?> expectedValues = (Collection<?>) expectedClaimValue;\n                Collection<?> actualValues = actualClaimValue instanceof Collection ? (Collection<?>) actualClaimValue :\n                        Collections.setOf(actualClaimValue);\n                for (Object expectedValue : expectedValues) {\n                    if (!Collections.contains(actualValues.iterator(), expectedValue)) {\n                        String msg = String.format(MISSING_EXPECTED_CLAIM_VALUE_MESSAGE_TEMPLATE,\n                                expectedValue, expectedClaimName, actualValues);\n                        throw new IncorrectClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);\n                    }\n                }\n            } else if (!expectedClaimValue.equals(actualClaimValue)) {\n                String msg = String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE,\n                        expectedClaimName, expectedClaimValue, actualClaimValue);\n                throw new IncorrectClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    public <T> T parse(CharSequence compact, JwtHandler<T> handler) {\n        return parse(compact, Payload.EMPTY).accept(handler);\n    }\n\n    private Jwt<?, ?> parse(CharSequence compact, Payload unencodedPayload) {\n        Assert.hasText(compact, \"JWT String argument cannot be null or empty.\");","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L747-L783","documentation":"Thrown as IncorrectClaimException when a claim required via require(claimName, collection) is present but does not contain one of the expected values. JJWT converts the actual claim value to a collection (using it directly if it is already a Collection, otherwise wrapping it in a set) and checks that every expected value is contained in it.","triggerScenarios":"parser.require(\"aud\", Set.of(\"audience-a\",\"audience-b\")) where the token's 'aud' claim exists but lacks one of the expected values — e.g. aud is 'audience-a' only, or contains values not in the expected set.","commonSituations":"Audience mismatch between issuer and consumer configurations (wrong client ID / audience registered); role/scope lists changed on the issuer but expected sets on the consumer are stale; tokens minted for a different environment (prod aud vs staging verifier).","solutions":["Update the expected collection in require(...) to match what the issuer actually emits (decode the token to inspect the real values).","Fix the token issuer to include the expected value in the claim.","If the consumer registered for multiple audiences, add its own identifier to the issuer's aud list.","Log the token's actual claim values (or catch IncorrectClaimException and read its message) to diagnose the exact mismatch."],"exampleFix":"// before\nJwts.parser().require(\"aud\", List.of(\"api-prod\")).verifyWith(key).build().parse(jwt); // token aud=[\"api-staging\"]\n// after\nJwts.parser().require(\"aud\", List.of(\"api-prod\", \"api-staging\")).verifyWith(key).build().parse(jwt);\n// or fix issuer: Jwts.builder().audience().add(\"api-prod\").and()...","handlingStrategy":"validation","validationCode":"io.jsonwebtoken.Claims c = Jwts.parser().build().parseUnsecuredClaims(jwt).getPayload();\njava.util.List<?> aud = c.get(\"aud\", java.util.List.class);\njava.util.Set<String> expected = java.util.Set.of(\"api-prod\");\nif (aud == null || java.util.Collections.disjoint(aud, expected)) {\n    throw new IllegalStateException(\"aud mismatch: \" + aud);\n}","typeGuard":null,"tryCatchPattern":"try {\n    claims = Jwts.parser().require(\"aud\", expectedAudiences).verifyWith(key).build().parseSignedClaims(jwt).getPayload();\n} catch (io.jsonwebtoken.IncorrectClaimException e) {\n    // message names the missing expected value and actual values\n}","preventionTips":["Keep accepted audience/scope lists in configuration, updated alongside issuer changes","Use environment-specific expected values (staging vs prod)","Decode a real producer token before freezing the expected set","Catch IncorrectClaimException and log actual vs expected for diagnostics"],"tags":["jwt","claims-validation","audience-mismatch"],"backgroundTag":"jwt-claim-validation-failed","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}