{"record":{"id":"4245f0459b86d703","repo":"jwtk/jjwt","slug":"invalid-claims-t-getmessage","errorCode":null,"errorMessage":"Invalid claims: + t.getMessage()","messagePattern":"Invalid claims: \\+ t\\.getMessage\\(\\)","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":630,"sourceCode":"                        // mark/reset isn't possible, we'll need to buffer:\n                        if (!in.markSupported()) {\n                            in = new BufferedInputStream(in);\n                            in.mark(0);\n                        }\n                        claimsMap = deserialize(new UncloseableInputStream(in) /* Don't close in case we need to rewind */, \"claims\");\n                    } catch (DeserializationException |\n                             MalformedJwtException ignored) { // not JSON, treat it as a byte[]\n//                String msg = \"Invalid claims: \" + e.getMessage();\n//                throw new MalformedJwtException(msg, e);\n                    } finally {\n                        Streams.reset(in);\n                    }\n                    if (claimsMap != null) {\n                        try {\n                            claims = new DefaultClaims(claimsMap);\n                        } catch (Throwable t) {\n                            String msg = \"Invalid claims: \" + t.getMessage();\n                            throw new MalformedJwtException(msg);\n                        }\n                    }\n                }\n                if (claims == null) {\n                    // consumable, but not claims, so convert to byte array:\n                    payloadBytes = Streams.bytes(in, \"Unable to convert payload to byte array.\");\n                }\n            } finally { // always ensure closed per https://github.com/jwtk/jjwt/issues/949\n                Objects.nullSafeClose(in);\n            }\n        }\n\n        // =============== Post-SKR Signature Check =================\n        if (hasDigest && signingKeyResolver != null) { // TODO: remove for 1.0\n            // A SigningKeyResolver has been configured, and due to it's API, we have to verify the signature after\n            // parsing the body.  This can be a security risk, so it needs to be removed before 1.0\n            JwsHeader jwsHeader = Assert.stateIsInstance(JwsHeader.class, header, \"Not a JwsHeader. \");\n            digest = verifySignature(tokenized, jwsHeader, alg, this.signingKeyResolver, claims, payload);","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L612-L648","documentation":"After integrity verification, the parser converts the JWT payload map into a DefaultClaims object. If the map contains values that violate the Claims contract (bad types for standard claims like exp/iat/nbf, non-string iss/sub, etc.), the constructor throws and the parser wraps it as a MalformedJwtException with the underlying message.","triggerScenarios":"Parsing a JWT whose claims map has wrong-typed or invalid registered claims — e.g. exp as a string instead of a numeric date, null reserved claim values, nested structures DefaultClaims rejects.","commonSituations":"Tokens minted by other libraries (e.g. emitting ISO date strings for exp), tokens serialized with a generic JSON mapper losing numeric types, proxy/middleware rewriting claim values to strings.","solutions":["Fix the token producer to serialize registered claims per RFC 7519 (NumericDate: seconds since epoch as a number).","Catch MalformedJwtException and log t.getMessage() to identify which claim failed, then inspect the raw payload (base64url-decode the middle segment).","If you control deserialization of foreign tokens, pre-parse the payload yourself and normalize claim types before JJWT parsing.","Upgrade JJWT if an older version rejects a valid claim layout fixed in later releases."],"exampleFix":"// before (producer)\nclaims.put(\"exp\", Instant.now().plus(1, HOURS).toString());\n// after\nclaims.setExpiration(Date.from(Instant.now().plus(1, HOURS)));","handlingStrategy":"try-catch","validationCode":"// pre-validate registered claim types on the raw payload map\nObject exp = claimsMap.get(\"exp\");\nif (exp != null && !(exp instanceof Number)) throw new IllegalArgumentException(\"exp must be NumericDate (number)\");","typeGuard":null,"tryCatchPattern":"try { parser.parseSignedClaims(token); } catch (MalformedJwtException e) { log.warn(\"Invalid claims payload: {}\", e.getMessage()); /* decode payload manually to inspect */ }","preventionTips":["Use JJWT's ClaimsBuilder/ JwtBuilder to mint tokens so claim types are always correct.","When interoperating with other libraries, check how they serialize exp/iat/nbf (must be numeric seconds).","Round-trip test cross-language token exchange in CI.","Never put null values into reserved claim names."],"tags":["claims","malformed-jwt","type-mismatch","rfc7519"],"backgroundTag":"schema-validation-failed","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}