{"id":"1c4cfb8b100e2b24","repo":"google/gson","slug":"expected-number-but-was-token-location","errorCode":null,"errorMessage":"Expected NUMBER but was {token}{location}","messagePattern":"Expected NUMBER but was (.+?)(.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java","lineNumber":243,"sourceCode":"      pathIndices[stackSize - 1]++;\n    }\n    return result;\n  }\n\n  @Override\n  public void nextNull() throws IOException {\n    expect(JsonToken.NULL);\n    popStack();\n    if (stackSize > 0) {\n      pathIndices[stackSize - 1]++;\n    }\n  }\n\n  @Override\n  public double nextDouble() throws IOException {\n    JsonToken token = peek();\n    if (token != JsonToken.NUMBER && token != JsonToken.STRING) {\n      throw new IllegalStateException(\n          \"Expected \" + JsonToken.NUMBER + \" but was \" + token + locationString());\n    }\n    JsonPrimitive primitive = (JsonPrimitive) peekStack();\n    double result;\n    try {\n      result = primitive.getAsDouble();\n    } catch (NumberFormatException e) {\n      throw numberFormatException(\"Expected a double but was \" + primitive.getAsString(), e);\n    }\n    if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {\n      throw new MalformedJsonException(\"JSON forbids NaN and infinities: \" + result);\n    }\n    popStack();\n    if (stackSize > 0) {\n      pathIndices[stackSize - 1]++;\n    }\n    return result;\n  }","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java#L225-L261","documentation":"JsonTreeReader.nextDouble throws IllegalStateException('Expected NUMBER but was ' + token + locationString) when the current token is neither NUMBER nor STRING. nextDouble accepts STRING as a convenience (it parses the string to double), but rejects BOOLEAN, NULL, NAME, BEGIN_*, END_*. The {token} is the actual JsonToken, {location} the path.","triggerScenarios":"Calling nextDouble() when the reader sits on a boolean, null, object, or array. Common when deserializing a numeric field whose value is missing (NULL) or accidentally encoded as a nested object.","commonSituations":"Numeric field changed to nullable in a new API version (null instead of 0); field swapped from number to boolean flag; wrong key being read so the cursor lands on a structural token.","solutions":["Branch on in.peek() before nextDouble(): handle NULL with nextNull(), handle STRING with explicit parse if allowed, reject other tokens.","If the field can legitimately be null, make the Java field a boxed Double and read null explicitly.","Validate the JSON shape before deserializing, or use a JsonElement capture +getAsDouble() with your own error handling.","Fix the producer to emit the numeric value consistently."],"exampleFix":"// before\ndouble v = in.nextDouble(); // throws if token is NULL\n\n// after\nDouble v;\nif (in.peek() == JsonToken.NULL) { in.nextNull(); v = null; }\nelse { v = in.nextDouble(); }","handlingStrategy":"type-guard","validationCode":"JsonToken t = reader.peek();\nif (t != JsonToken.NUMBER && t != JsonToken.STRING) {\n  throw new IllegalStateException(\"Expected number at \" + reader.getPath() + \", got \" + t);\n}\ndouble v = reader.nextDouble();","typeGuard":"static boolean isNumberOrStringToken(JsonReader r) throws IOException {\n  JsonToken t = r.peek();\n  return t == JsonToken.NUMBER || t == JsonToken.STRING;\n}","tryCatchPattern":"try {\n  return reader.nextDouble();\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Expected NUMBER\")) {\n    throw new InvalidPayloadException(\"Expected numeric field at \" + reader.getPath(), e);\n  }\n  throw e;\n}","preventionTips":["Handle NULL explicitly when numeric fields are nullable.","Use boxed Double for optional numeric fields.","Validate the JSON shape with a schema when strict typing matters."],"tags":["jsonreader","json-tree","number","type-adapter"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}