jwtk/jjwt · error · io.jsonwebtoken.io.SerializationException
Cannot serialize ${name} to JSON. Cause: ${t.getMessage()}
Error message
Cannot serialize ${name} to JSON. Cause: ${t.getMessage()} What it means
Thrown as a SerializationException when the delegate JSON serializer fails to write the given claims Map to the output stream. The message names the entity being serialized (e.g. 'JWT payload') and includes the underlying cause. Any Throwable during delegate.serialize is wrapped here.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/NamedSerializer.java:42
import java.util.Map;
public class NamedSerializer extends AbstractSerializer<Map<String, ?>> {
private final String name;
private final Serializer<Map<String, ?>> DELEGATE;
public NamedSerializer(String name, Serializer<Map<String, ?>> serializer) {
this.DELEGATE = Assert.notNull(serializer, "JSON Serializer cannot be null.");
this.name = Assert.hasText(name, "Name cannot be null or empty.");
}
@Override
protected void doSerialize(Map<String, ?> m, OutputStream out) throws SerializationException {
try {
this.DELEGATE.serialize(m, out);
} catch (Throwable t) {
String msg = String.format("Cannot serialize %s to JSON. Cause: %s", this.name, t.getMessage());
throw new SerializationException(msg, t);
}
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Inspect the cause message: unserializable types are the most frequent root cause.
- Convert claim values to JSON-friendly types (String, Number, Boolean, Map, List) before serializing.
- Register a JJWT Serializer (e.g. Jackson or Gson based) that supports your custom types via converters.
- Verify the target OutputStream is open and writable.
Example fix
// before
claims.put("expires", new Date()); // unserializable without converter
Jwts.builder().setClaims(claims).compact();
// after
claims.put("expires", new Date().getTime() / 1000); // JSON-friendly number
Jwts.builder().setClaims(claims).compact(); Defensive patterns
Strategy: type-guard
Validate before calling
// Java
static void assertJsonFriendly(Map<String,?> claims) {
for (Map.Entry<String,?> e : claims.entrySet()) {
Object v = e.getValue();
boolean ok = v == null || v instanceof String || v instanceof Number
|| v instanceof Boolean || v instanceof Map || v instanceof List;
if (!ok) throw new IllegalArgumentException(
"Claim '" + e.getKey() + "' has non-JSON type: " + v.getClass().getName());
}
} Type guard
static boolean isJsonFriendly(Object v) {
return v == null || v instanceof String || v instanceof Number
|| v instanceof Boolean || v instanceof Map || v instanceof List;
} Try / catch
try {
String jwt = Jwts.builder().setClaims(claims).compact();
} catch (SerializationException e) {
log.error("Claims not serializable: {}", e.getMessage(), e.getCause());
throw new IllegalArgumentException("Claims contain non-JSON-friendly values", e);
} Prevention
- Store only JSON-friendly types (String, Number, Boolean, Map, List) in claims.
- Represent dates as epoch seconds/millis numbers, not java.util.Date objects.
- Register a JJWT Serializer (Jackson/Gson) suited to your object model at bootstrap.
- Check the exception cause to pinpoint which claim value failed serialization.
When it happens
Trigger: Calling serialize on NamedSerializer with a Map containing values the JSON serializer cannot handle (unserializable types, cyclic references, non-JSON-friendly objects like Date without a converter) or when the target OutputStream fails.
Common situations: Putting custom Java objects (Date, BigDecimal with unusual settings, POJOs without registered converters) into claims; cyclic object graphs; OutputStream write failures (closed stream, disk full).
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- Unable to serialize object of type ${className}: ${e.getMess
- Unable to deserialize: ${t.getMessage()}
- Unable to encode input: ${e.getMessage()}
- Unable to serialize object of type to JSON using known heur
- Invalid protected header: ${e.getMessage()}
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/ae75b0f45e228417.
Report an issue: GitHub.