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

  1. 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.
  2. Ensure the JSON being deserialized was produced by a serializer that writes floats as JSON numbers, not strings.
  3. 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

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

Related errors


AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13). Data as JSON: /api/errors/895928810efd686c. Report an issue: GitHub.