{"record":{"id":"94275535c850e404","repo":"google/gson","slug":"expected-number-but-was-token-at-path-path","errorCode":null,"errorMessage":"Expected NUMBER but was ${token} at path ${path}","messagePattern":"Expected NUMBER but was (.+?) at path (.+?)","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/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java#L225-L261","documentation":"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.","triggerScenarios":"Deserializing a double field whose JSON value is a boolean, null, object, or array, when the source is a JsonElement tree (JsonTreeReader).","commonSituations":"Schema drift where a numeric field starts receiving booleans/objects; null literal reaching a non-nullSafe double adapter.","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."],"exampleFix":"// before: {\"amount\":null} into non-nullSafe double\nGson().fromJson(\"{\\\"amount\\\":null}\", Price::class.java) // Expected NUMBER\n\n// after: {\"amount\":0.0}\nGson().fromJson(\"{\\\"amount\\\":0.0}\", Price::class.java)","handlingStrategy":"validation","validationCode":"// Validate token type before nextDouble\nJsonToken t = reader.peek();\nif (t == NUMBER || t == STRING) {\n  double d = reader.nextDouble();\n} else {\n  // missing or wrong type\n  reader.skipValue();\n}","typeGuard":null,"tryCatchPattern":"try {\n  reader.nextDouble();\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Expected NUMBER\")) {\n    reader.skipValue(); // tolerate wrong type\n  } else throw e;\n}","preventionTips":["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."],"tags":["json-tree-reader","token","number","type-mismatch"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}