google/gson · error · InvalidObjectException

Deserialization is unsupported

Error message

Deserialization is unsupported

What it means

LinkedTreeMap.writeReplace() emits a LinkedHashMap so non-Gson consumers can deserialize it; LinkedTreeMap.readObject() throws InvalidObjectException to prevent directly reconstructing the AVL-backed form, which would bypass its DoS defenses and invariants (LinkedTreeMap.java:672). Triggered only by deserialization paths that bypass writeReplace.

Solutions

  1. Do not serialize LinkedTreeMap directly; rely on writeReplace and deserialize the LinkedHashMap replacement.
  2. Convert to LinkedHashMap explicitly before writing: oos.writeObject(new LinkedHashMap<>(treeMap)).
  3. Avoid using Java serialization for Gson-internal containers; use Gson itself to (de)serialize the data as JSON.

Example fix

// before
oos.writeObject(linkedTreeMap); // later readObject() may throw
// after
oos.writeObject(new LinkedHashMap<>(linkedTreeMap));
Defensive patterns

Strategy: validation

Validate before calling

Object toWrite = (obj instanceof LinkedTreeMap) ? new LinkedHashMap<>((LinkedTreeMap<?,?>) obj) : obj;

Type guard

static boolean isLinkedTreeMap(Object o) { return o instanceof com.google.gson.internal.LinkedTreeMap; }

Try / catch

try { ois.readObject(); } catch (InvalidObjectException e) { /* stream was tampered; reject */ }

Prevention

When it happens

Trigger: An ObjectInputStream stream whose class descriptor names LinkedTreeMap and reaches readObject, e.g. via a tampered stream or a custom ObjectInputStream that ignores/overrides resolveClass resolution of the replacement.

Common situations: Custom Java-serialization harnesses; cross-process RMI/serialization tests with Gson's internal map; maliciously crafted streams; tests that re-serialize and re-deserialize JsonObject state.

Related errors


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

Appendix: 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 defense, 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 310ac341f2)