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

  1. Convert the POJO to a Map<String,Object> (manually or via Jackson) before adding it as a claim
  2. Only use JSON-native claim values: String, Number, Boolean, Map, List, null
  3. Register a full Serializer implementation (Jackson/Gson) instead of the orgjson one if POJO support is needed
  4. 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

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


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