google/gson · error · IllegalArgumentException
Couldn't write {class}
Error message
Couldn't write {class} What it means
JsonElementTypeAdapter.write throws IllegalArgumentException('Couldn't write ' + value.getClass()) when the JsonElement passed for serialization is not null/jsonNull, not a primitive, not an array, and not an object. The built-in writer only knows how to emit those four shapes; a user-defined JsonElement subclass falls into the final else branch. The {class} is the unsupported JsonElement subclass.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java:168
}
} else if (value.isJsonArray()) {
out.beginArray();
for (JsonElement e : value.getAsJsonArray()) {
write(out, e);
}
out.endArray();
} else if (value.isJsonObject()) {
out.beginObject();
for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {
out.name(e.getKey());
write(out, e.getValue());
}
out.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + value.getClass());
}
}
}
View on GitHub (pinned to 8b8628c656)
Solutions
- Avoid subclassing JsonElement; favor composition (hold a JsonObject field) instead of inheritance.
- If you must subclass, ensure you do not override isJsonObject()/isJsonArray()/isJsonPrimitive()/isJsonNull() to return false for your type — better, convert to a standard JsonObject before serializing.
- Before calling toJson, normalize: JsonObject std = custom.toStandardJsonObject(); gson.toJson(std).
- If you control the writer path, register a custom TypeAdapter<JsonElement> that handles your subclass.
Example fix
// before
class TaggedObject extends JsonObject { String tag; } // isJsonObject() may still be true, but...
// if a subclass breaks isJsonObject() -> IllegalArgumentException('Couldn't write ' + class)
// after: compose, don't subclass
class TaggedObject { String tag; JsonObject payload = new JsonObject(); }
gson.toJson(tagged); // serialize the composed JsonObject via its own adapter Defensive patterns
Strategy: type-guard
Validate before calling
// Reject unsupported JsonElement subclasses before serializing
if (!(element instanceof JsonObject) && !(element instanceof JsonArray)
&& !(element instanceof JsonPrimitive) && !(element instanceof JsonNull)) {
throw new IllegalArgumentException("Unsupported JsonElement: " + element.getClass());
} Type guard
static boolean isWritableJsonElement(JsonElement e) {
return e == null || e.isJsonNull() || e.isJsonObject()
|| e.isJsonArray() || e.isJsonPrimitive();
} Try / catch
try {
gson.toJson(element);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Couldn't write ")) {
throw new IllegalArgumentException("Unsupported JsonElement subclass; convert to JsonObject", e);
}
throw e;
} Prevention
- Never subclass JsonElement; compose with a JsonObject field instead.
- Validate the element type before serializing when receiving trees from third-party code.
- Normalize custom elements to standard JsonObject/JsonArray at the boundary.
When it happens
Trigger: A user subclasses JsonElement (or JsonObject/JsonArray) and overrides identity in a way that makes isJsonObject()/isJsonArray()/isJsonPrimitive()/isJsonNull() all return false, then passes the instance to Gson.toJson / Streams.write / JsonElementTypeAdapter.write.
Common situations: Custom JSON tree types intended to add metadata; defensive subclasses that break instanceof checks; libraries that extend JsonObject to add ordering/typing and forget to keep isJsonObject() true.
Related errors
- Custom JsonElement subclass {className} is not supported
- cannot serialize {srcType.getName()}; did you forget to regi
- cannot serialize {srcType.getName()} because it already defi
- Deserialization is unsupported
- Deserialization is unsupported
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/7212b3ee4c56c966.json.
Report an issue: GitHub.