{"id":"5f4b5132b24805d1","repo":"google/gson","slug":"custom-jsonelement-subclass-classname-is-not-sup","errorCode":null,"errorMessage":"Custom JsonElement subclass {className} is not supported","messagePattern":"Custom JsonElement subclass (.+?) is not supported","errorType":"exception","errorClass":"MalformedJsonException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java","lineNumber":168,"sourceCode":"    } else if (o instanceof JsonArray) {\n      return JsonToken.BEGIN_ARRAY;\n    } else if (o instanceof JsonPrimitive) {\n      JsonPrimitive primitive = (JsonPrimitive) o;\n      if (primitive.isString()) {\n        return JsonToken.STRING;\n      } else if (primitive.isBoolean()) {\n        return JsonToken.BOOLEAN;\n      } else if (primitive.isNumber()) {\n        return JsonToken.NUMBER;\n      } else {\n        throw new AssertionError();\n      }\n    } else if (o instanceof JsonNull) {\n      return JsonToken.NULL;\n    } else if (o == SENTINEL_CLOSED) {\n      throw new IllegalStateException(\"JsonReader is closed\");\n    } else {\n      throw new MalformedJsonException(\n          \"Custom JsonElement subclass \" + o.getClass().getName() + \" is not supported\");\n    }\n  }\n\n  private Object peekStack() {\n    return stack[stackSize - 1];\n  }\n\n  @CanIgnoreReturnValue\n  private Object popStack() {\n    Object result = stack[--stackSize];\n    stack[stackSize] = null;\n    return result;\n  }\n\n  private void expect(JsonToken expected) throws IOException {\n    if (peek() != expected) {\n      throw new IllegalStateException(","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java#L150-L186","documentation":"JsonTreeReader.peek throws MalformedJsonException('Custom JsonElement subclass ' + className + ' is not supported') when the top of the stack is an object that is not Iterator, JsonObject, JsonArray, JsonPrimitive, JsonNull, or the closed sentinel — i.e. a user-defined JsonElement subclass that the tree reader cannot classify. The {className} identifies the offending class.","triggerScenarios":"Constructing a JsonTreeReader over a JsonElement tree that contains a custom JsonElement subclass (one that fails the instanceof checks for JsonObject/JsonArray/JsonPrimitive/JsonNull). Happens when a custom JsonElement type sneaks into a tree that is then parsed back through JsonTreeReader.","commonSituations":"User JsonElement subclasses carrying metadata; adapters that splice non-standard element types into a JsonObject; libraries that extend JsonObject but break instanceof identity.","solutions":["Avoid subclassing JsonElement; use only JsonObject, JsonArray, JsonPrimitive, JsonNull in trees you hand to JsonTreeReader/Gson.","Normalize any custom element to a standard JsonObject before constructing a JsonTreeReader.","If you control the source, replace custom elements with their plain equivalents.","Register a custom TypeAdapter if you truly need a non-standard element shape, and skip JsonTreeReader."],"exampleFix":"// before\nclass Tagged extends JsonElement { /* custom */ }\nJsonObject root = new JsonObject(); root.add(\"x\", new Tagged());\nnew JsonTreeReader(root).peek(); // MalformedJsonException\n\n// after: store plain JsonPrimitive / JsonObject\nJsonObject root = new JsonObject(); root.addProperty(\"x\", 1);\nnew JsonTreeReader(root).peek(); // BEGIN_OBJECT","handlingStrategy":"type-guard","validationCode":"// Walk the tree and reject custom JsonElement subclasses before constructing a reader\nstatic void assertStandard(JsonElement e) {\n  if (e instanceof JsonObject) { ((JsonObject) e).values().forEach(JsonGuard::assertStandard); }\n  else if (e instanceof JsonArray) { ((JsonArray) e).forEach(JsonGuard::assertStandard); }\n  else if (!(e instanceof JsonPrimitive) && !(e instanceof JsonNull)) {\n    throw new IllegalArgumentException(\"Unsupported JsonElement: \" + e.getClass());\n  }\n}","typeGuard":"static boolean isStandardJsonElement(Object o) {\n  return o instanceof JsonObject || o instanceof JsonArray\n      || o instanceof JsonPrimitive || o instanceof JsonNull;\n}","tryCatchPattern":"try {\n  new JsonTreeReader(element).peek();\n} catch (MalformedJsonException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Custom JsonElement subclass\")) {\n    throw new IllegalArgumentException(\"Tree contains a custom JsonElement subclass\", e);\n  }\n  throw e;\n}","preventionTips":["Use only the four standard JsonElement types in trees.","Normalize custom element types at the boundary before parsing.","Audit third-party code that produces JsonElement trees."],"tags":["jsonelement","json-tree","subclass","reader"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}