google/gson · error · MalformedJsonException

Custom JsonElement subclass ${className} is not supported

Error message

Custom JsonElement subclass ${className} is not supported

What it means

JsonTreeReader only recognizes JsonObject, JsonArray, JsonPrimitive, and JsonNull on its stack. When peek encounters an object that is none of these (a user-defined JsonElement subclass), it throws MalformedJsonException. This guards the tree-walk against types Gson never produces itself.

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java:168

    } else if (o instanceof JsonArray) {
      return JsonToken.BEGIN_ARRAY;
    } else if (o instanceof JsonPrimitive) {
      JsonPrimitive primitive = (JsonPrimitive) o;
      if (primitive.isString()) {
        return JsonToken.STRING;
      } else if (primitive.isBoolean()) {
        return JsonToken.BOOLEAN;
      } else if (primitive.isNumber()) {
        return JsonToken.NUMBER;
      } else {
        throw new AssertionError();
      }
    } else if (o instanceof JsonNull) {
      return JsonToken.NULL;
    } else if (o == SENTINEL_CLOSED) {
      throw new IllegalStateException("JsonReader is closed");
    } else {
      throw new MalformedJsonException(
          "Custom JsonElement subclass " + o.getClass().getName() + " is not supported");
    }
  }

  private Object peekStack() {
    return stack[stackSize - 1];
  }

  @CanIgnoreReturnValue
  private Object popStack() {
    Object result = stack[--stackSize];
    stack[stackSize] = null;
    return result;
  }

  private void expect(JsonToken expected) throws IOException {
    if (peek() != expected) {
      throw new IllegalStateException(

View on GitHub (pinned to 310ac341f2)

Solutions

  1. Do not subclass JsonElement; use JsonObject/JsonArray/JsonPrimitive/JsonNull directly.
  2. Convert the custom element to a JsonObject before parsing.
  3. Register a TypeAdapter that handles your custom type instead of relying on tree-reading.

Example fix

// before
class MyObj : JsonElement() { ... }
val reader = JsonTreeReader(MyObj())
reader.peek() // Custom JsonElement subclass is not supported

// after: use standard JsonObject
val reader = JsonTreeReader(JsonObject().apply { addProperty("k", 1) })
reader.peek()
Defensive patterns

Strategy: type-guard

Validate before calling

// Reject custom JsonElement subclasses before building a tree reader
static boolean isSupportedTreeElement(JsonElement e) {
  return e == null || e.isJsonNull() || e.isJsonObject() || e.isJsonArray() || e.isJsonPrimitive();
}
if (!isSupportedTreeElement(root)) throw new IllegalArgumentException("Unsupported element");
new JsonTreeReader(root).peek();

Type guard

static boolean isStandardJsonElement(JsonElement e) {
  return e instanceof JsonObject || e instanceof JsonArray
      || e instanceof JsonPrimitive || e instanceof JsonNull;
}

Try / catch

try {
  new JsonTreeReader(element).peek();
} catch (MalformedJsonException e) {
  if (e.getMessage().startsWith("Custom JsonElement subclass")) {
    // convert to JsonObject and retry
    new JsonTreeReader(toJsonObject(element)).peek();
  } else throw e;
}

Prevention

When it happens

Trigger: Constructing a JsonTreeReader (directly or by passing a JsonElement to Gson) whose root or nested element is an instance of a custom JsonElement subclass that does not extend one of the four standard types.

Common situations: Subclassing JsonElement/JsonObject and feeding instances into gson.fromJson(element, type); libraries that introduce proxy JsonElement types.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/009ac5c7a9171aae. Report an issue: GitHub.