jwtk/jjwt · error · IOException
Unable to serialize object of type to JSON using known heur
Error message
Unable to serialize object of type to JSON using known heuristics.
What it means
OrgJsonSerializer.toJSONInstance throws IOException when the object to serialize is not a JSON-compatible type (Map, Collection, primitive/String/Number/Boolean, JSONObject/JSONArray, etc.) and no known heuristic can convert it. org.json has no JavaBean marshaller, so arbitrary POJOs are rejected.
Source
Thrown at extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java:130
if (object instanceof Map) {
Map<?, ?> map = (Map<?, ?>) object;
return toJSONObject(map);
}
if (Objects.isArray(object)) {
object = Collections.arrayToList(object); //sets object to List, will be converted in next if-statement:
}
if (object instanceof Collection) {
Collection<?> coll = (Collection<?>) object;
return toJSONArray(coll);
}
//not an immediately JSON-compatible object and probably a JavaBean (or similar). We can't convert that
//directly without using a marshaller of some sort:
String msg = "Unable to serialize object of type " + object.getClass().getName() + " to JSON using known heuristics.";
throw new IOException(msg);
}
private JSONObject toJSONObject(Map<?, ?> m) throws IOException {
JSONObject obj = new JSONObject();
for (Map.Entry<?, ?> entry : m.entrySet()) {
Object k = entry.getKey();
Object value = entry.getValue();
String key = String.valueOf(k);
value = toJSONInstance(value);
obj.put(key, value);
}
return obj;
}
View on GitHub (pinned to fb71496164)
Solutions
- Convert the POJO to a Map<String,Object> (manually or via Jackson) before adding it as a claim
- Only use JSON-native claim values: String, Number, Boolean, Map, List, null
- Register a full Serializer implementation (Jackson/Gson) instead of the orgjson one if POJO support is needed
- Add a toMap()/toJSON() method on your POJO and pass that
Example fix
// before
Jwts.builder().claim("user", userPojo); // IOException on serialize
// after
Map<String, Object> userMap = new HashMap<>();
userMap.put("id", userPojo.getId());
Jwts.builder().claim("user", userMap); Defensive patterns
Strategy: type-guard
Validate before calling
static boolean isJsonCompatible(Object o) {
return o == null || o instanceof Map || o instanceof Collection || o instanceof String
|| o instanceof Number || o instanceof Boolean || o instanceof org.json.JSONObject
|| o instanceof org.json.JSONArray || (o != null && o.getClass().isArray());
} Type guard
see validationCode isJsonCompatible(Object)
Try / catch
try {
String json = serializer.serialize(value, out);
} catch (IOException e) {
if (e.getMessage().startsWith("Unable to serialize object of type")) {
value = convertToMap(value); // fallback converter
} else throw e;
} Prevention
- Restrict JWT claim values to JSON-native types (String, Number, Boolean, Map, List)
- Add an explicit toMap() on domain objects placed in claims
- If POJO support is required, use the Jackson or Gson extension serializer instead of orgjson
- Test claim round-trips (build then parse) for every claim type you use
When it happens
Trigger: Calling Jwts.builder().claims().add(...) or the orgjson Serializer with a custom POJO/complex object as a claim value that is not a Map, Collection, array, or primitive wrapper.
Common situations: Putting domain entities (User, Address) directly into JWT claims; nesting custom types inside claims; forgetting that only JSON-native types are supported without a custom serializer.
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
- Invalid Gson instance - it has not been registered with the
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
- Unexpected Claims JWS.
- Unexpected content JWE.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/f5efac31521c3e85.
Report an issue: GitHub.