google/gson · error · NumberFormatException
Expected a long but was {}{}
Error message
Expected a long but was {}{} What it means
Thrown by JsonReader.nextLong() (JsonReader.java:1124-1127) when the literal was read as a string, parsed as a double, and casting back to long changed the value (result != asDouble). This means the JSON number had a fractional part or magnitude that cannot be represented exactly as a long. It is a NumberFormatException, not an IOException, to signal a value-conversion failure rather than a malformed stream.
Source
Thrown at gson/src/main/java/com/google/gson/stream/JsonReader.java:1126
// Fall back to parse as a double below.
}
} else {
throw unexpectedTokenError("a long");
}
peeked = PEEKED_BUFFERED;
double asDouble;
try {
asDouble = Double.parseDouble(peekedString);
} catch (NumberFormatException e) {
NumberFormatException rethrown =
new NumberFormatException("Expected a long but was " + peekedString + locationString());
rethrown.initCause(e);
throw rethrown;
}
long result = (long) asDouble;
if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
throw new NumberFormatException("Expected a long but was " + peekedString + locationString());
}
peekedString = null;
peeked = PEEKED_NONE;
pathIndices[stackSize - 1]++;
return result;
}
/**
* Returns the string up to but not including {@code quote}, unescaping any character escape
* sequences encountered along the way. The opening quote should have already been read. This
* consumes the closing quote, but does not include it in the returned string.
*
* @param quote either ' or ".
*/
private String nextQuotedValue(char quote) throws IOException {
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
char[] buffer = this.buffer;
StringBuilder builder = null;View on GitHub (pinned to 310ac341f2)
Solutions
- Use nextDouble() instead of nextLong() if the value may be fractional.
- Validate with peek()==JsonToken.NUMBER and pre-check the literal before committing to nextLong.
- Round or truncate explicitly: Math.round(reader.nextDouble()).
- Align the JSON producer to emit integers for integral fields.
Example fix
// before long id = reader.nextLong(); // fails on "3.14" // after long id = (long) reader.nextDouble();
Defensive patterns
Strategy: validation
Validate before calling
if (reader.peek() == JsonToken.STRING || reader.peek() == JsonToken.NUMBER) {
String raw = reader.nextString();
long v = new BigDecimal(raw).setScale(0, RoundingMode.DOWN).longValueExact();
}
// or simply widen the field:
long v = (long) reader.nextDouble(); Type guard
static boolean isExactLong(String literal) {
try { Long.parseLong(literal); return true; }
catch (NumberFormatException e) { return false; }
} Try / catch
try {
return reader.nextLong();
} catch (NumberFormatException e) {
return (long) reader.nextDouble(); // best-effort, only if appropriate
} Prevention
- Use nextLong only for fields guaranteed integral and within long range.
- Prefer nextDouble for potentially fractional JSON numbers.
- Inspect the JSON schema to confirm a field's numeric type.
When it happens
Trigger: Calling nextLong() on a JSON value like 3.14, 1e10 (lossy), or a string "3.5". The reader first tries Long.parseLong; on failure it falls back to Double.parseDouble and then checks that (long)asDouble == asDouble, throwing here when it does not.
Common situations: API that returns numbers as decimals or strings in JSON; switching a field from nextDouble to nextLong without verifying the producer; locale-agnostic stringified numbers; mixed schemas where a field is sometimes integral and sometimes a float.
Related errors
- Expected an int but was {}{}
- End of input{}
- Invalid nesting limit: {}
- JsonReader is closed
- Nesting limit {} reached{}
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/c944ec32da070a4c.
Report an issue: GitHub.