dotnet/BenchmarkDotNet · error · JsonException
Unexpected token {reader.TokenType} when parsing float.
Error message
Unexpected token {reader.TokenType} when parsing float. What it means
Thrown by SimpleJsonFloatConverter.Read during JSON deserialization when the token at the current position is not a JsonTokenType.Number. The custom converter handles the serialization of float.NaN, float.PositiveInfinity, and float.NegativeInfinity by writing them as empty strings, but on read it only accepts numeric tokens. Any non-number token (including the empty string written for NaN/Infinity) triggers this JsonException.
Source
Thrown at src/BenchmarkDotNet/Serialization/BdnSimpleJsonSerializer.cs:53
public static string Serialize<T>(T item, bool indentJson = false)
{
if (indentJson)
return JsonSerializer.Serialize(item, IndentedOptions);
else
return JsonSerializer.Serialize(item, DefaultOptions);
}
/// <summary>
/// Custom JsonConverter for float that write Nan/PositiveInfinite/NegativeInfinite as empty string.
/// </summary>
private class SimpleJsonFloatConverter : JsonConverter<float>
{
public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Number)
return reader.GetSingle();
throw new JsonException($"Unexpected token {reader.TokenType} when parsing float.");
}
public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
{
if (float.IsNaN(value) || float.IsInfinity(value))
writer.WriteStringValue("");
else
writer.WriteNumberValue(value);
}
}
/// <summary>
/// Custom JsonConverter for double that write Nan/PositiveInfinite/NegativeInfinite as empty string.
/// </summary>
private class SimpleJsonDoubleConverter : JsonConverter<double>
{
public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{View on GitHub (pinned to b515068b61)
Solutions
- If round-tripping NaN/Infinity is needed, the converter's Read method must handle string tokens (including empty string) — this may require a custom converter override or a library fix.
- Ensure the JSON being deserialized was produced by a serializer that writes floats as JSON numbers, not strings.
- Filter or sanitize NaN/Infinity values from statistics before serialization if re-import is required.
Example fix
// The converter's Read only accepts numbers:
if (reader.TokenType == JsonTokenType.Number)
return reader.GetSingle();
throw new JsonException(...);
// To handle round-tripped NaN/Infinity (empty string),
// a fix would extend Read:
// if (reader.TokenType == JsonTokenType.String)
// return float.NaN; // or parse appropriately Defensive patterns
Strategy: validation
Validate before calling
// Before deserializing, check if JSON contains string-encoded floats
using var doc = JsonDocument.Parse(jsonString);
foreach (var prop in doc.RootElement.EnumerateObject())
if (prop.Value.ValueKind == JsonValueKind.String && prop.Name.Contains("float", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("JSON contains string-encoded float values that cannot be deserialized by BdnSimpleJsonSerializer."); Try / catch
try
{
var result = JsonSerializer.Deserialize<MyModel>(json, BdnSimpleJsonSerializer.Options);
}
catch (JsonException ex) when (ex.Message.Contains("parsing float"))
{
// The float was serialized as a string (NaN/Infinity). Use default System.Text.Json options instead.
var result = JsonSerializer.Deserialize<MyModel>(json);
} Prevention
- For JSON that needs round-tripping, use System.Text.Json's default options instead of BdnSimpleJsonSerializer.
- Sanitize NaN/Infinity values from statistics before serializing if re-import is needed.
- Be aware that BdnSimpleJsonSerializer's Write and Read are asymmetric for special float values.
When it happens
Trigger: Deserializing JSON that contains a float field encoded as a string (including the empty string that the Write method uses for NaN/Infinity), a null token, or a property name where a number is expected. The mismatch between Write (which can emit empty strings) and Read (which rejects them) means round-tripping NaN/Infinity values through this serializer will fail on read.
Common situations: Exporting benchmark results containing NaN or Infinity statistics to JSON via BdnSimpleJsonSerializer, then trying to re-import them. Reading JSON from an external source that represents floats as strings.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13).
Data as JSON: /api/errors/895928810efd686c.
Report an issue: GitHub.