google/gson · error · InvalidObjectException
Deserialization is unsupported
Error message
Deserialization is unsupported
What it means
Thrown by LazilyParsedNumber.readObject(ObjectInputStream) as InvalidObjectException. LazilyParsedNumber is an internal Gson type that stores a JSON number as a string and converts lazily. Its writeReplace() serializes it as a BigDecimal, so direct Java deserialization back into a LazilyParsedNumber is intentionally blocked to keep the serialized form portable and dependency-free.
Source
Thrown at gson/src/main/java/com/google/gson/internal/LazilyParsedNumber.java:91
}
@Override
public String toString() {
return value;
}
/**
* If somebody is unlucky enough to have to serialize one of these, serialize it as a BigDecimal
* so that they won't need Gson on the other side to deserialize it.
*/
private Object writeReplace() {
return asBigDecimal();
}
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");
}
/**
* Compares this LazilyParsedNumber with the specified LazilyParsedNumber. The comparison is
* lexicographical, based on the string values of the two numbers, so it does not in general
* correspond to numeric comparison. For numeric comparison, call {@link #asBigDecimal()} on both
* numbers and compare the results.
*/
@Override
public int compareTo(LazilyParsedNumber other) {
return value.compareTo(other.value);
}
@Override
public int hashCode() {
return value.hashCode();
}
View on GitHub (pinned to 8b8628c656)
Solutions
- Do not serialize LazilyParsedNumber directly; serialize the value as a BigDecimal or a String and reconstruct via new LazilyParsedNumber(string).
- If reading a stored stream, reserialize the source data through Gson (toJson/fromJson) instead of Java serialization.
- Upgrade Gson; ensure writeReplace is active by not overriding it in subclasses.
Example fix
// before: Java-serializing an internal Gson number ObjectOutputStream out = ... out.writeObject(gsonNumber); // LazilyParsedNumber ObjectInputStream in = ... Number n = (Number) in.readObject(); // InvalidObjectException // after: serialize as BigDecimal/JSON out.writeObject(gsonNumber instanceof LazilyParsedNumber ? new BigDecimal(gsonNumber.toString()) : gsonNumber);
Defensive patterns
Strategy: try-catch
Validate before calling
// Before serializing a Number from Gson, convert to a portable form
static Number portable(Number n) {
return (n instanceof LazilyParsedNumber) ? new BigDecimal(n.toString()) : n;
}
// usage: out.writeObject(portable(gsonNumber)); Type guard
static boolean isPortableNumber(Number n) {
return !(n.getClass().getName().contains("LazilyParsedNumber"));
} Try / catch
try {
Object o = in.readObject();
} catch (InvalidObjectException e) {
if (e.getMessage().contains("Deserialization is unsupported")) {
// reserialize the source via JSON instead of Java serialization
throw new IllegalStateException("Use Gson JSON transport, not Java serialization", e);
} else throw e;
} Prevention
- Never Java-serialize internal Gson types; use toJson/fromJson.
- Convert LazilyParsedNumber to BigDecimal before persisting.
- Keep serialization confined to plain JDK collections and primitives.
When it happens
Trigger: Calling ObjectInputStream.readObject() on a stream that was serialized from a LazilyParsedNumber without going through its writeReplace (e.g. a tampered or legacy stream, or reflection-based deserialization that bypasses the replacement). Normal serialization writes a BigDecimal and reads a BigDecimal, so this only fires when the stream claims to be a LazilyParsedNumber directly.
Common situations: Deserializing a legacy object graph that was serialized with an old or buggy Gson version that did not install writeReplace; tampered/forged streams; custom ObjectInputStream subclasses that resolve classes manually; debugging tools that read raw object streams.
Related errors
- Deserialization is unsupported
- Number string too large: {value}...
- Number has unsupported scale: {s}
- JSON forbids NaN and infinities: {value}
- memberDescription + " is not accessible and ReflectionAccess
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/1a710e0dd139dc47.json.
Report an issue: GitHub.