{"record":{"id":"c944ec32da070a4c","repo":"google/gson","slug":"expected-a-long-but-was","errorCode":null,"errorMessage":"Expected a long but was {}{}","messagePattern":"Expected a long but was (.+?)(.+?)","errorType":"exception","errorClass":"NumberFormatException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/stream/JsonReader.java","lineNumber":1126,"sourceCode":"        // Fall back to parse as a double below.\n      }\n    } else {\n      throw unexpectedTokenError(\"a long\");\n    }\n\n    peeked = PEEKED_BUFFERED;\n    double asDouble;\n    try {\n      asDouble = Double.parseDouble(peekedString);\n    } catch (NumberFormatException e) {\n      NumberFormatException rethrown =\n          new NumberFormatException(\"Expected a long but was \" + peekedString + locationString());\n      rethrown.initCause(e);\n      throw rethrown;\n    }\n    long result = (long) asDouble;\n    if (result != asDouble) { // Make sure no precision was lost casting to 'long'.\n      throw new NumberFormatException(\"Expected a long but was \" + peekedString + locationString());\n    }\n    peekedString = null;\n    peeked = PEEKED_NONE;\n    pathIndices[stackSize - 1]++;\n    return result;\n  }\n\n  /**\n   * Returns the string up to but not including {@code quote}, unescaping any character escape\n   * sequences encountered along the way. The opening quote should have already been read. This\n   * consumes the closing quote, but does not include it in the returned string.\n   *\n   * @param quote either ' or \".\n   */\n  private String nextQuotedValue(char quote) throws IOException {\n    // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.\n    char[] buffer = this.buffer;\n    StringBuilder builder = null;","sourceCodeStart":1108,"sourceCodeEnd":1144,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/stream/JsonReader.java#L1108-L1144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlong id = reader.nextLong(); // fails on \"3.14\"\n\n// after\nlong id = (long) reader.nextDouble();","handlingStrategy":"validation","validationCode":"if (reader.peek() == JsonToken.STRING || reader.peek() == JsonToken.NUMBER) {\n  String raw = reader.nextString();\n  long v = new BigDecimal(raw).setScale(0, RoundingMode.DOWN).longValueExact();\n}\n// or simply widen the field:\nlong v = (long) reader.nextDouble();","typeGuard":"static boolean isExactLong(String literal) {\n  try { Long.parseLong(literal); return true; }\n  catch (NumberFormatException e) { return false; }\n}","tryCatchPattern":"try {\n  return reader.nextLong();\n} catch (NumberFormatException e) {\n  return (long) reader.nextDouble(); // best-effort, only if appropriate\n}","preventionTips":["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."],"tags":["java","gson","jsonreader","numeric","parsing"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}