{"record":{"id":"2ea62b287f2916ab","repo":"google/gson","slug":"couldn-t-write-class","errorCode":null,"errorMessage":"Couldn't write ${class}","messagePattern":"Couldn't write (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java","lineNumber":168,"sourceCode":"      }\n\n    } else if (value.isJsonArray()) {\n      out.beginArray();\n      for (JsonElement e : value.getAsJsonArray()) {\n        write(out, e);\n      }\n      out.endArray();\n\n    } else if (value.isJsonObject()) {\n      out.beginObject();\n      for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {\n        out.name(e.getKey());\n        write(out, e.getValue());\n      }\n      out.endObject();\n\n    } else {\n      throw new IllegalArgumentException(\"Couldn't write \" + value.getClass());\n    }\n  }\n}\n","sourceCodeStart":150,"sourceCodeEnd":172,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/JsonElementTypeAdapter.java#L150-L172","documentation":"JsonElementTypeAdapter.write handles null/JsonNull, JsonPrimitive, JsonArray, JsonObject. The final else branch throws IllegalArgumentException when the value is a JsonElement subclass that reports none of these (e.g. isJsonNull/isJsonPrimitive/isJsonArray/isJsonObject all return false), which happens with custom JsonElement subclasses.","triggerScenarios":"Calling gson.toJson(element) or Streams.write where element is a user-defined subclass of JsonElement that does not behave as one of the four standard subtypes, or where the subclass overrides isJsonNull etc. to return false.","commonSituations":"Extending JsonElement/JsonObject to add domain methods and serializing instances directly; library code that wraps JsonElement in a proxy subclass.","solutions":["Avoid subclassing JsonElement; favor composition over inheritance.","Register a custom TypeAdapter for your JsonElement subclass via GsonBuilder.registerTypeAdapter.","Convert the custom element to a standard JsonObject before serializing.","If you must subclass, ensure isJsonPrimitive/isJsonArray/isJsonObject/isJsonNull behave correctly."],"exampleFix":"// before\nclass MyElement : JsonElement() { ... }\ngson.toJson(MyElement()) // Couldn't write MyElement\n\n// after: register an adapter, or convert\ngson.toJson(MyElement().toStandardObject())","handlingStrategy":"type-guard","validationCode":"// Convert custom JsonElement to a standard JsonObject before serializing\nstatic JsonElement normalize(JsonElement e) {\n  if (e.isJsonObject() || e.isJsonArray() || e.isJsonPrimitive() || e.isJsonNull()) return e;\n  JsonObject o = new JsonObject();\n  o.add(\"data\", new JsonPrimitive(e.toString()));\n  return o;\n}\nStreams.write(normalize(customElement), writer);","typeGuard":"static boolean isStandardJsonElement(JsonElement e) {\n  return e == null || e.isJsonNull() || e.isJsonObject() || e.isJsonArray() || e.isJsonPrimitive();\n}","tryCatchPattern":"try {\n  Streams.write(element, writer);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Couldn't write \")) {\n    // custom JsonElement subclass; convert and retry\n    Streams.write(toJsonObject(element), writer);\n  } else throw e;\n}","preventionTips":["Do not subclass JsonElement; compose instead.","If subclassing is unavoidable, register a custom TypeAdapter for it.","Convert custom elements to JsonObject before serialization.","Add a unit test that serializes every JsonElement variant you use."],"tags":["json-element","serialization","custom-subclass"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}