jwtk/jjwt · error · SerializationException
Unable to serialize object of type ${className}: ${e.getMess
Error message
Unable to serialize object of type ${className}: ${e.getMessage()} What it means
JJWT wraps any unexpected Throwable thrown while serializing an object (typically the JWT claim map) into bytes into a SerializationException. AbstractSerializer.serialize catches failures from doSerialize that are not already SerializationException instances and rethrows them with the object's class name and the underlying message. The class name in the message tells you exactly which object failed to convert.
Source
Thrown at api/src/main/java/io/jsonwebtoken/io/AbstractSerializer.java:60
public final byte[] serialize(T t) throws SerializationException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(t, out);
return out.toByteArray();
}
/**
* {@inheritDoc}
*/
@Override
public final void serialize(T t, OutputStream out) throws SerializationException {
try {
doSerialize(t, out);
} catch (Throwable e) {
if (e instanceof SerializationException) {
throw (SerializationException) e;
}
String msg = "Unable to serialize object of type " + Objects.nullSafeClassName(t) + ": " + e.getMessage();
throw new SerializationException(msg, e);
}
}
/**
* Converts the specified Java object into a formatted data byte stream, writing the bytes to the specified
* {@code out}put stream.
*
* @param t the object to convert to a byte stream
* @param out the stream to write to
* @throws Exception if there is a problem converting the object to a byte stream or writing the
* bytes to the {@code out}put stream.
* @since 0.12.0
*/
protected abstract void doSerialize(T t, OutputStream out) throws Exception;
}
View on GitHub (pinned to fb71496164)
Solutions
- Read the cause and the class name in the message; ensure that type is JSON-serializable by the configured runtime (Jackson or Gson)
- Simplify claim values to primitives, Strings, Dates, Maps, and Lists, or register a serializer/converter for the custom type
- Fix Jackson visibility issues (add getters or @JsonProperty/@JsonAutoDetect) when 'No serializer found' is the cause
- If you implemented a custom Serializer, wrap failures in SerializationException inside doSerialize so they propagate unchanged
Example fix
// before
jws = Jwts.builder().setClaims(Map.of("user", hibernateLazyProxy)).compact();
// Unable to serialize object of type User$HibernateProxy$...: ...
// after
jws = Jwts.builder().claim("userId", user.getId()).compact(); // serialize plain values Defensive patterns
Strategy: validation
Validate before calling
// Java: ensure claim values are JSON-safe before building the JWT
static boolean isJsonSafe(Object v) {
if (v == null) return true;
if (v instanceof String || v instanceof Number || v instanceof Boolean) return true;
if (v instanceof java.util.Date || v instanceof java.util.Calendar) return true;
if (v instanceof Map<?,?> m) return m.values().stream().allMatch(MyClaims::isJsonSafe);
if (v instanceof java.util.Collection<?> c) return c.stream().allMatch(MyClaims::isJsonSafe);
if (v instanceof byte[] || v instanceof char[]) return true;
return false;
} Type guard
boolean isSerializableClaim(Object v) {
return v == null || v instanceof String || v instanceof Number
|| v instanceof Boolean || v instanceof java.util.Date
|| v instanceof Map || v instanceof java.util.Collection;
} Try / catch
try {
String jws = Jwts.builder().setClaims(claims).signWith(key).compact();
} catch (SerializationException e) {
// e.getCause() holds the underlying serializer failure
} Prevention
- Restrict claim values to primitives, Strings, Dates, Maps, and Lists
- Never place lazy ORM proxies or framework-managed entities directly into claims
- Register Jackson serializers/modules for any custom types you must include
- Verify getters/visibility for beans serialized by Jackson (avoid 'No serializer found')
- Wrap failures in SerializationException inside any custom Serializer's doSerialize
When it happens
Trigger: Serializing a claims map or payload containing a value the underlying JSON runtime cannot handle — e.g. an object with no Jackson/Gson serializer, a JDK type the runtime rejects, circular object references, or a custom Serializer whose doSerialize throws (IOException, IllegalArgumentException, etc.).
Common situations: Putting non-JSON-friendly values in claims (Date handled by default, but custom types like BufferedImage, Hibernate lazy proxies, or enums without registered serializers); Jackson failing with 'No serializer found' due to no getters and visibility config; classpath version mismatch between JJWT and Jackson/Gson; a custom Serializer that throws raw exceptions.
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
- Cannot serialize ${name} to JSON. Cause: ${t.getMessage()}
- 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/5cd45bb94b53ff57.
Report an issue: GitHub.