jwtk/jjwt · error · DeserializationException

Unable to deserialize: ${t.getMessage()}

Error message

Unable to deserialize: ${t.getMessage()}

What it means

io.jsonwebtoken (JJWT) wraps any unexpected Throwable thrown while deserializing a byte/char stream back into a Java object into a DeserializationException. This wrapper is produced by AbstractDeserializer.deserialize when doDeserialize throws something that is not already a DeserializationException (e.g. a RuntimeException from the underlying parser). The original cause is preserved via the cause chain, so inspect getCause() for the real problem.

Source

Thrown at api/src/main/java/io/jsonwebtoken/io/AbstractDeserializer.java:72

        InputStream in = new ByteArrayInputStream(bytes);
        Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
        return deserialize(reader);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final T deserialize(Reader reader) throws DeserializationException {
        Assert.notNull(reader, "Reader argument cannot be null.");
        try {
            return doDeserialize(reader);
        } catch (Throwable t) {
            if (t instanceof DeserializationException) {
                throw (DeserializationException) t;
            }
            String msg = "Unable to deserialize: " + t.getMessage();
            throw new DeserializationException(msg, t);
        }
    }

    /**
     * Reads the specified character stream and returns the corresponding Java object.
     *
     * @param reader the reader to use to read the character stream
     * @return the deserialized Java object
     * @throws Exception if there is a problem reading the stream or creating the expected Java object
     */
    protected abstract T doDeserialize(Reader reader) throws Exception;
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Inspect the exception's getCause() to find the underlying parser error and fix that root cause first
  2. Verify the token/payload string is valid, complete JSON (not truncated, not HTML, no whitespace corruption from URL handling)
  3. Ensure a supported JSON runtime (Jackson or Gson) is on the classpath at a version compatible with your JJWT release
  4. If you implemented a custom Deserializer, wrap parser failures in DeserializationException inside doDeserialize so the original error type is propagated

Example fix

// before
Claims claims = Jwts.parserBuilder().build()
    .parseClaimsJws(corruptedToken).getBody(); // Unable to deserialize: ...

// after
try {
    Claims claims = Jwts.parserBuilder().build()
        .parseClaimsJws(token.trim()).getBody();
} catch (DeserializationException e) {
    log.error("Bad token payload: {}", e.getCause()); // inspect root cause
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Java: sanity-check the token text before parsing
boolean isPlausibleJwt(String token) {
    return token != null && token.chars().filter(c -> c == '.').count() == 2
        && !token.isBlank();
}

Type guard

boolean isDeserializationSafe(java.io.Reader r) {
    return r != null; // content validity is delegated to the parser; guard nulls and catch DeserializationException
}

Try / catch

try {
    Claims claims = Jwts.parserBuilder().build().parseClaimsJws(token).getBody();
} catch (DeserializationException e) {
    Throwable root = e.getCause();
    // handle malformed payload; log root cause
}

Prevention

When it happens

Trigger: Calling any JJWT API that must deserialize a payload or claim map (e.g. Jwts.parser().parseClaimsJws(...) with a serialized body, or a custom Serializer/Deserializer implementation whose doDeserialize throws an undeclared exception such as Jackson's JsonParseException, ClassNotFoundException, or a NullPointerException).

Common situations: Passing truncated, corrupted, or non-JSON base64url payload text to the parser; a classpath mismatch where the Jackson/Gson runtime is a different version than JJWT expects; deserializing a payload into a custom type whose class is missing at runtime; a custom Deserializer that throws raw exceptions instead of DeserializationException.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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