{"record":{"id":"3e432c007948fe29","repo":"dotnet/BenchmarkDotNet","slug":"unexpected-token-reader-tokentype-when-parsing-d","errorCode":null,"errorMessage":"Unexpected token {reader.TokenType} when parsing double.","messagePattern":"Unexpected token (.+?) when parsing double\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/BenchmarkDotNet/Serialization/BdnSimpleJsonSerializer.cs","lineNumber":75,"sourceCode":"        {\n            if (float.IsNaN(value) || float.IsInfinity(value))\n                writer.WriteStringValue(\"\");\n            else\n                writer.WriteNumberValue(value);\n        }\n    }\n\n    /// <summary>\n    /// Custom JsonConverter for double that write Nan/PositiveInfinite/NegativeInfinite as empty string.\n    /// </summary>\n    private class SimpleJsonDoubleConverter : JsonConverter<double>\n    {\n        public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            if (reader.TokenType == JsonTokenType.Number)\n                return reader.GetSingle();\n\n            throw new JsonException($\"Unexpected token {reader.TokenType} when parsing double.\");\n        }\n\n        public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)\n        {\n            if (double.IsNaN(value) || double.IsInfinity(value))\n                writer.WriteStringValue(\"\");\n            else\n                writer.WriteNumberValue(value);\n        }\n    }\n}\n","sourceCodeStart":57,"sourceCodeEnd":87,"githubUrl":"https://github.com/dotnet/BenchmarkDotNet/blob/b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3/src/BenchmarkDotNet/Serialization/BdnSimpleJsonSerializer.cs#L57-L87","documentation":"Thrown by SimpleJsonDoubleConverter.Read during JSON deserialization when the current token is not a JsonTokenType.Number. Similar to the float converter, the Write method encodes NaN/PositiveInfinity/NegativeInfinity as empty strings, but Read rejects all non-number tokens. Additionally, the Read method has a latent bug: it calls reader.GetSingle() (returning float) instead of reader.GetDouble(), which truncates precision on valid double values — this is a separate correctness issue beyond the exception itself.","triggerScenarios":"Deserializing JSON with double fields encoded as strings, null tokens, or the empty strings produced by Write for NaN/Infinity. The asymmetry between Write (emits empty string) and Read (rejects non-number) means JSON exported with this serializer cannot be safely re-imported if it contains NaN/Infinity.","commonSituations":"Exporting benchmark statistics (which frequently contain NaN for standard deviation of single-sample runs or Infinity in ratio calculations) to JSON and re-importing. Reading externally-produced JSON with string-encoded doubles.","solutions":["For round-trip support, the Read method needs to handle string tokens (including empty string for NaN/Infinity) — this requires a library-level fix or custom converter.","Ensure the input JSON encodes doubles as JSON numbers, not strings.","Be aware of the GetSingle() vs GetDouble() precision bug: even when deserialization succeeds, doubles may lose precision. Report or patch this if high-precision values matter.","Prefer the default System.Text.Json double handling for interop if BdnSimpleJsonSerializer's custom behavior is not required."],"exampleFix":"// Current Read has two issues:\n// 1. Calls GetSingle() instead of GetDouble() (precision loss)\n// 2. Rejects string tokens that Write emits for NaN/Infinity\n\n// A corrected Read:\npublic override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n{\n    if (reader.TokenType == JsonTokenType.Number)\n        return reader.GetDouble(); // fix: was GetSingle()\n    if (reader.TokenType == JsonTokenType.String)\n    {\n        var s = reader.GetString();\n        return string.IsNullOrEmpty(s) ? double.NaN : double.Parse(s);\n    }\n    throw new JsonException($\"Unexpected token {reader.TokenType} when parsing double.\");\n}","handlingStrategy":"validation","validationCode":"// Before deserializing, check for string-encoded doubles in the JSON\nusing var doc = JsonDocument.Parse(jsonString);\nforeach (var prop in doc.RootElement.EnumerateObject())\n    if (prop.Value.ValueKind == JsonValueKind.String && prop.Name.Contains(\"double\", StringComparison.OrdinalIgnoreCase))\n        throw new InvalidOperationException(\"JSON contains string-encoded double values that cannot be deserialized by BdnSimpleJsonSerializer.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var result = JsonSerializer.Deserialize<MyModel>(json, BdnSimpleJsonSerializer.Options);\n}\ncatch (JsonException ex) when (ex.Message.Contains(\"parsing double\"))\n{\n    // The double was serialized as a string (NaN/Infinity). Use default System.Text.Json options instead.\n    var result = JsonSerializer.Deserialize<MyModel>(json);\n}","preventionTips":["For round-tripping JSON with doubles, prefer System.Text.Json's default options over BdnSimpleJsonSerializer.","Filter NaN/Infinity values from data before serialization if re-import is required.","Be aware of the precision bug: BdnSimpleJsonSerializer's double Read calls GetSingle(), truncating precision — report or patch if needed.","Run a round-trip test (serialize then deserialize) to catch converter asymmetries before production use."],"tags":["serialization","json","double","json-exception","bug"],"backgroundTag":null,"analyzedSha":"b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3","analyzedAt":"2026-08-13T19:12:24.196Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}