google/gson · error · InvalidObjectException

Deserialization is unsupported

Error message

Deserialization is unsupported

What it means

Thrown by LinkedTreeMap.readObject(ObjectInputStream) as InvalidObjectException. LinkedTreeMap's writeReplace() converts it to a LinkedHashMap on serialization so the receiver does not need Gson; direct Java deserialization back into a LinkedTreeMap is therefore intentionally blocked. The class comment also notes Java serialization defeats Gson's DoS defences, so it is discouraged.

Source

Thrown at gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java:675

    @Override
    public void clear() {
      LinkedTreeMap.this.clear();
    }
  }

  /**
   * If somebody is unlucky enough to have to serialize one of these, serialize it as a
   * LinkedHashMap so that they won't need Gson on the other side to deserialize it. Using
   * serialization defeats our DoS defence, so most apps shouldn't use it.
   */
  private Object writeReplace() throws ObjectStreamException {
    return new LinkedHashMap<>(this);
  }

  private void readObject(ObjectInputStream in) throws IOException {
    // Don't permit directly deserializing this class; writeReplace() should have written a
    // replacement
    throw new InvalidObjectException("Deserialization is unsupported");
  }
}

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Do not Java-serialize LinkedTreeMap; persist via Gson JSON (toJson/fromJson) instead.
  2. If you must use Java serialization, copy entries into a LinkedHashMap before serializing and read them back as a LinkedHashMap.
  3. Upgrade Gson and avoid storing raw internal map instances in serialized fields.

Example fix

// before
ObjectOutputStream out = ...
out.writeObject(linkedTreeMap); // internal type
ObjectInputStream in = ...
Map<?,?> m = (Map<?,?>) in.readObject(); // InvalidObjectException

// after: serialize as a standard map or JSON
out.writeObject(new LinkedHashMap<>(linkedTreeMap));
Defensive patterns

Strategy: try-catch

Validate before calling

// Convert to a portable map before Java serialization
static Map<?, ?> portable(Map<?, ?> m) {
  return new LinkedHashMap<>(m);
}
// usage: out.writeObject(portable(linkedTreeMap));

Type guard

static boolean isJavaSerializableMap(Object o) {
  return o instanceof LinkedHashMap || o instanceof HashMap;
}

Try / catch

try {
  Object o = in.readObject();
} catch (InvalidObjectException e) {
  if (e.getMessage().contains("Deserialization is unsupported")) {
    // switch to JSON-based persistence
    throw new IllegalStateException("Persist via Gson JSON, not Java serialization", e);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling ObjectInputStream.readObject() on a stream whose root object is tagged as a LinkedTreeMap (bypassing writeReplace), e.g. a forged, legacy, or manually constructed stream. Normal serialization writes a LinkedHashMap and reads a LinkedHashMap, so this fires only on non-standard streams.

Common situations: Deserializing an object graph persisted by an old Gson version or a buggy custom ObjectOutputStream; tampered streams; testing tooling that constructs object streams directly; interop with another JVM language that bypasses writeReplace.

Related errors


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