jwtk/jjwt · error · DeserializationException

${String.format(MALFORMED_COMPLEX_ERROR, this.name, this.nam

Error message

${String.format(MALFORMED_COMPLEX_ERROR, this.name, this.name, e.getMessage())}

What it means

Thrown as a DeserializationException when deserializing a JSON structure causes a StackOverflowError. jjwt catches this specifically because deeply nested JSON payloads (e.g. thousands of '[' or '{' characters) overflow the recursive parser and would otherwise crash the JVM thread. The formatted message names the value being parsed ('MALFORMED_COMPLEX_ERROR') and the underlying cause.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/JsonObjectDeserializer.java:70

            value = this.deserializer.deserialize(in);
            if (value == null) {
                String msg = "Deserialized data resulted in a null value; cannot create Map<String,?>";
                throw new DeserializationException(msg);
            }
            if (!(value instanceof Map)) {
                String msg = "Deserialized data is not a JSON Object; cannot create Map<String,?>";
                throw new DeserializationException(msg);
            }
            // JSON Specification requires all JSON Objects to have string-only keys.  So instead of
            // checking that the val.keySet() has all Strings, we blindly cast to a Map<String,?>
            // since input would rarely, if ever, have non-string keys.
            //noinspection unchecked
            return (Map<String, ?>) value;
        } catch (StackOverflowError e) {
            String msg = String.format(MALFORMED_COMPLEX_ERROR, this.name, this.name, e.getMessage());
            throw new DeserializationException(msg, e);
        } catch (Throwable t) {
            throw malformed(t);
        }
    }

    protected RuntimeException malformed(Throwable t) {
        String msg = String.format(MALFORMED_ERROR, this.name, t.getMessage());
        throw new MalformedJwtException(msg, t);
    }
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Treat the token as malformed and reject it — do not retry; the input is the problem.
  2. Validate token structure (e.g. limit payload size and nesting) before passing it to the parser.
  3. Increase thread stack size (-Xss) only as a stopgap; prefer rejecting the input.
  4. Catch DeserializationException (or MalformedJwtException's superclass JwtException) and return 4xx to the caller.

Example fix

// before
Claims c = Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload(); // DeserializationException on deep nesting
// after
try {
    Claims c = Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload();
} catch (MalformedJwtException e) {
    throw new BadJwtTokenException("Malformed JWT payload", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// reject tokens with suspiciously large or deep payloads before parsing
if (token.length() > MAX_TOKEN_LENGTH) throw new BadJwtTokenException("JWT too large");

Type guard

// verify the compact JWT has exactly 3-5 dot-separated base64url segments
boolean wellFormed = token != null && token.matches("^[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+){2,4}$");

Try / catch

try {
    return Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
} catch (MalformedJwtException | DeserializationException e) {
    throw new BadJwtTokenException("Malformed JWT", e);
}

Prevention

When it happens

Trigger: Parsing a JWT whose payload or claims map contains extremely deeply nested JSON arrays/objects, so the streaming JSON deserializer recurses past the stack limit. Triggered via Jwts.parser().parse... on a maliciously or accidentally crafted token.

Common situations: Receiving untrusted JWTs from third parties; security fuzzing; logging giant nested payloads; test suites checking malformed-token handling.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/428816e4c927d8c1. Report an issue: GitHub.