{"record":{"id":"9480e560b4c48419","repo":"jwtk/jjwt","slug":"jwt-claim-expectedclaimname-was-expected-to-be","errorCode":null,"errorMessage":"JWT Claim '<expectedClaimName>' was expected to be a Date, but its value cannot be converted to a Date using current heuristics.  Value: <actualClaimValue>","messagePattern":"JWT Claim '<expectedClaimName>' was expected to be a Date, but its value cannot be converted to a Date using current heuristics\\.  Value: <actualClaimValue>","errorType":"exception","errorClass":"IncorrectClaimException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":744,"sourceCode":"        return o;\n    }\n\n    private void validateExpectedClaims(Header header, Claims claims) {\n\n        final Claims expected = expectedClaims.build();\n\n        for (String expectedClaimName : expected.keySet()) {\n\n            Object expectedClaimValue = normalize(expected.get(expectedClaimName));\n            Object actualClaimValue = normalize(claims.get(expectedClaimName));\n\n            if (expectedClaimValue instanceof Date) {\n                try {\n                    actualClaimValue = claims.get(expectedClaimName, Date.class);\n                } catch (Exception e) {\n                    String msg = \"JWT Claim '\" + expectedClaimName + \"' was expected to be a Date, but its value \" +\n                            \"cannot be converted to a Date using current heuristics.  Value: \" + actualClaimValue;\n                    throw new IncorrectClaimException(header, claims, expectedClaimName, expectedClaimValue, msg);\n                }\n            }\n\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)) {","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L726-L762","documentation":"Thrown as IncorrectClaimException by require(...) claim validation when the expected claim value passed to the parser is a Date (or Calendar), but the actual claim in the token cannot be converted to a Date using JJWT's heuristics (long epoch millis, ISO-8601 string, etc.). This means a requiredDate(...) call found a claim whose value is of an unparseable type/format.","triggerScenarios":"parser.require(claimName, someDate) where the JWT contains claimName with a value that is neither a numeric epoch-millis nor a recognized date string (e.g. an arbitrary object, boolean, or malformed text).","commonSituations":"Issuer serializes dates as non-standard formats (e.g. '01/02/2024', human-readable text, or nested objects); a JWT library on the producing side emits dates as seconds-instead-of-millis strings with non-numeric characters; claims populated programmatically with wrong types.","solutions":["Fix the token producer to emit the claim as epoch-millis (long) or ISO-8601 date string.","Inspect the actual token payload (base64-decode the claims section) to see the raw value and adjust your expectation type.","If the claim is genuinely not a date, change the require() call to require(name, correctExpectedValue) of matching type.","Add a custom claim converter/serializer on the issuing side so dates round-trip in a standard format."],"exampleFix":"// before\nString jwt = Jwts.builder().claim(\"iat\", \"yesterday\").compact(); // unparseable\nClaims c = Jwts.parser().build().parseSignedClaims(jwt).getPayload();\nJwts.parser().require(\"iat\", new Date()).build().parse(jwt); // IncorrectClaimException\n// after\nString jwt = Jwts.builder().claim(\"iat\", System.currentTimeMillis()).compact();\nJwts.parser().require(\"iat\", new Date()).build().parse(jwt); // OK","handlingStrategy":"validation","validationCode":"Object raw = io.jsonwebtoken.Jwts.parser().build().parseUnsecuredClaims(jwt).getPayload().get(\"iat\");\nboolean isDateLike = raw instanceof Number ||\n    (raw instanceof String s && s.matches(\"\\\\d{10,13}|\\\\d{4}-\\\\d{2}-\\\\d{2}T.*\"));\nif (!isDateLike) throw new IllegalArgumentException(\"Claim 'iat' is not date-like: \" + raw);","typeGuard":"boolean isDateLike(Object v) {\n    return v instanceof Date || v instanceof Number\n        || (v instanceof String s && (s.matches(\"\\\\d+\") || s.matches(\"\\\\d{4}-\\\\d{2}-\\\\d{2}T.+\")));\n}","tryCatchPattern":"try {\n    Jwts.parser().require(\"exp\", expiryDate).build().parse(jwt);\n} catch (io.jsonwebtoken.IncorrectClaimException e) {\n    // inspect e.getClaimName()/value; producer emitted a non-date format\n}","preventionTips":["Emit date claims as epoch-millis longs or ISO-8601 strings only","Contract-test the producer's claim types against consumer expectations","Never put human-readable dates or nested objects in date claims","Round-trip test: parse tokens your builder creates before shipping"],"tags":["jwt","claims-validation","date-format","type-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"}