google/gson · error · IllegalStateException
Expected NUMBER but was ${token} at path ${path}
Error message
Expected NUMBER but was ${token} at path ${path} What it means
JsonTreeReader.nextDouble accepts NUMBER or (in lenient mode) STRING tokens; any other token throws IllegalStateException. Called by adapters deserializing double/Double fields from a JsonElement tree.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java:243
pathIndices[stackSize - 1]++;
}
return result;
}
@Override
public void nextNull() throws IOException {
expect(JsonToken.NULL);
popStack();
if (stackSize > 0) {
pathIndices[stackSize - 1]++;
}
}
@Override
public double nextDouble() throws IOException {
JsonToken token = peek();
if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
throw new IllegalStateException(
"Expected " + JsonToken.NUMBER + " but was " + token + locationString());
}
JsonPrimitive primitive = (JsonPrimitive) peekStack();
double result;
try {
result = primitive.getAsDouble();
} catch (NumberFormatException e) {
throw numberFormatException("Expected a double but was " + primitive.getAsString(), e);
}
if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {
throw new MalformedJsonException("JSON forbids NaN and infinities: " + result);
}
popStack();
if (stackSize > 0) {
pathIndices[stackSize - 1]++;
}
return result;
}View on GitHub (pinned to 310ac341f2)
Solutions
- Ensure the JSON value for the field is a JSON number.
- Register a custom TypeAdapter that coerces or rejects gracefully.
- Make the adapter nullSafe if nulls are possible.
- Add contract tests asserting numeric types for the field.
Example fix
// before: {"amount":null} into non-nullSafe double
Gson().fromJson("{\"amount\":null}", Price::class.java) // Expected NUMBER
// after: {"amount":0.0}
Gson().fromJson("{\"amount\":0.0}", Price::class.java) Defensive patterns
Strategy: validation
Validate before calling
// Validate token type before nextDouble
JsonToken t = reader.peek();
if (t == NUMBER || t == STRING) {
double d = reader.nextDouble();
} else {
// missing or wrong type
reader.skipValue();
} Try / catch
try {
reader.nextDouble();
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Expected NUMBER")) {
reader.skipValue(); // tolerate wrong type
} else throw e;
} Prevention
- Emit JSON numbers for numeric fields on the producer side.
- Register a nullSafe TypeAdapter for double fields that may be absent.
- Validate numeric field shapes with contract tests.
When it happens
Trigger: Deserializing a double field whose JSON value is a boolean, null, object, or array, when the source is a JsonElement tree (JsonTreeReader).
Common situations: Schema drift where a numeric field starts receiving booleans/objects; null literal reaching a non-nullSafe double adapter.
Related errors
- Expected STRING but was ${token} at path ${path}
- Expected ${expected} but was ${peek} at path ${path}
- JSON forbids NaN and infinities: ${result}
- Number string too large: ${s.substring(0, 30)}...
- Number has unsupported scale: ${s}
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/94275535c850e404.
Report an issue: GitHub.