google/gson · error · MalformedJsonException

Custom JsonElement subclass {className} is not supported

Error message

Custom JsonElement subclass {className} is not supported

What it means

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.

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 8b8628c656)

Solutions

  1. Avoid subclassing JsonElement; use only JsonObject, JsonArray, JsonPrimitive, JsonNull in trees you hand to JsonTreeReader/Gson.
  2. Normalize any custom element to a standard JsonObject before constructing a JsonTreeReader.
  3. If you control the source, replace custom elements with their plain equivalents.
  4. Register a custom TypeAdapter if you truly need a non-standard element shape, and skip JsonTreeReader.

Example fix

// before
class Tagged extends JsonElement { /* custom */ }
JsonObject root = new JsonObject(); root.add("x", new Tagged());
new JsonTreeReader(root).peek(); // MalformedJsonException

// after: store plain JsonPrimitive / JsonObject
JsonObject root = new JsonObject(); root.addProperty("x", 1);
new JsonTreeReader(root).peek(); // BEGIN_OBJECT
Defensive patterns

Strategy: type-guard

Validate before calling

// Walk the tree and reject custom JsonElement subclasses before constructing a reader
static void assertStandard(JsonElement e) {
  if (e instanceof JsonObject) { ((JsonObject) e).values().forEach(JsonGuard::assertStandard); }
  else if (e instanceof JsonArray) { ((JsonArray) e).forEach(JsonGuard::assertStandard); }
  else if (!(e instanceof JsonPrimitive) && !(e instanceof JsonNull)) {
    throw new IllegalArgumentException("Unsupported JsonElement: " + e.getClass());
  }
}

Type guard

static boolean isStandardJsonElement(Object o) {
  return o instanceof JsonObject || o instanceof JsonArray
      || o instanceof JsonPrimitive || o instanceof JsonNull;
}

Try / catch

try {
  new JsonTreeReader(element).peek();
} catch (MalformedJsonException e) {
  if (e.getMessage() != null && e.getMessage().contains("Custom JsonElement subclass")) {
    throw new IllegalArgumentException("Tree contains a custom JsonElement subclass", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: User JsonElement subclasses carrying metadata; adapters that splice non-standard element types into a JsonObject; libraries that extend JsonObject but break instanceof identity.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/5f4b5132b24805d1.json. Report an issue: GitHub.