{"id":"e688810e8ac1005e","repo":"google/gson","slug":"expected-a-long-but-was-peekedstring-locatio","errorCode":null,"errorMessage":"Expected a long but was \" + peekedString + locationString()","messagePattern":"Expected a long but was \" \\+ peekedString \\+ locationString\\(\\)","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/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/stream/JsonReader.java#L1108-L1144","documentation":"Thrown by JsonReader.nextLong() as a NumberFormatException when the next token's value could be parsed as a double but loses precision when cast to long. This path is reached after the literal fails Long.parseLong but Double.parseDouble succeeds; the check `result != asDouble` detects the precision loss at JsonReader.java:1125.","triggerScenarios":"Calling nextLong() on a JSON value like 1.5, 1e10 (if not representable exactly as long), or a quoted string \"12345678901234567890\" whose double value does not equal its long truncation. The reader reads it as a double, casts to long, sees they differ, and throws.","commonSituations":"JSON sources that emit fractional numbers where the consumer expects integers; scientific-notation numbers; very large numeric IDs serialized as strings or doubles; schema mismatches between producer and consumer.","solutions":["Use nextDouble() if the value can legitimately be fractional, then convert yourself.","Fix the data source to emit integer literals representable as long.","Use nextString() and parse with BigInteger/BigDecimal if values may exceed long range.","Read with nextLong() only after confirming via peek() that the token is a NUMBER without a decimal/exponent."],"exampleFix":"// before\nlong id = reader.nextLong(); // throws for \"1.5\" or 1e20\n\n// after\ndouble d = reader.nextDouble();\nlong id = (long) d; // or use BigDecimal for arbitrary precision","handlingStrategy":"validation","validationCode":"// Check token shape before nextLong\nif (reader.peek() == JsonToken.NUMBER) {\n  // still may be fractional; read as string and test\n  String s = reader.nextString();\n  if (s.indexOf('.') >= 0 || s.indexOf('e') >= 0 || s.indexOf('E') >= 0) {\n    // not an integer literal; handle accordingly\n  } else {\n    long v = Long.parseLong(s);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return reader.nextLong();\n} catch (NumberFormatException e) {\n  // fall back to double or BigInteger parsing of the field\n  return fallbackParseLong(reader);\n}","preventionTips":["Use nextLong() only for fields known to be integer literals within long range.","Switch to nextDouble() or nextString()+BigDecimal for values that may be fractional or oversized.","Validate the JSON schema/producer to emit integer literals for integer fields.","Read large IDs as strings to avoid precision loss across platforms."],"tags":["gson","jsonreader","number-parsing","precision"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}