tursodatabase/turso · error · ArgumentException

Only finite numbers (not Infinity or NaN) can be passed as a

Error message

Only finite numbers (not Infinity or NaN) can be passed as arguments

What it means

The .NET serverless client encodes SQL parameters into Hrana protocol JSON before sending them. The JSON specification has no literals for Infinity or NaN, so the encoder refuses any non-finite float instead of producing a payload the server could never parse. The exception is thrown client-side, before any network request is made.

Source

Thrown at bindings/dotnet/src/Turso.Serverless.Client/HranaProtocol.cs:41

    public static readonly HranaValue Null = new() { Type = "null" };

    public static HranaValue Encode(object? value)
    {
        switch (value)
        {
            case null or DBNull:
                return Null;
            case bool b:
                return new HranaValue { Type = "integer", StringValue = b ? "1" : "0" };
            case sbyte or byte or short or ushort or int or uint or long:
                return new HranaValue { Type = "integer", StringValue = Convert.ToInt64(value, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) };
            case ulong ul:
                return new HranaValue { Type = "integer", StringValue = ul.ToString(CultureInfo.InvariantCulture) };
            case float f:
                return double.IsFinite(f)
                    ? new HranaValue { Type = "float", DoubleValue = f }
                    : throw new ArgumentException("Only finite numbers (not Infinity or NaN) can be passed as arguments");
            case double d:
                return double.IsFinite(d)
                    ? new HranaValue { Type = "float", DoubleValue = d }
                    : throw new ArgumentException("Only finite numbers (not Infinity or NaN) can be passed as arguments");
            case decimal m:
                return new HranaValue { Type = "float", DoubleValue = (double)m };
            case string s:
                return new HranaValue { Type = "text", StringValue = s };
            case char c:
                return new HranaValue { Type = "text", StringValue = c.ToString() };
            case Guid g:
                return new HranaValue { Type = "text", StringValue = g.ToString() };
            case DateTime dt:
                return new HranaValue { Type = "text", StringValue = dt.ToString("o", CultureInfo.InvariantCulture) };
            case DateTimeOffset dto:
                return new HranaValue { Type = "text", StringValue = dto.ToString("o", CultureInfo.InvariantCulture) };
            case byte[] bytes:
                return new HranaValue { Type = "blob", BlobValue = bytes };

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Map non-finite floats to a sentinel before binding: DBNull.Value for NULL, or 0/text per your schema
  2. Validate with float.IsFinite(value) at the boundary where the value enters your application
  3. If NaN/Infinity must be stored, encode them as TEXT (e.g. "NaN") in a TEXT column
  4. Fix the upstream computation producing NaN/Infinity — usually a divide-by-zero or an uninitialized accumulator

Example fix

// before
float ratio = total / count; // 0/0 -> NaN
cmd.Parameters.AddWithValue("@r", ratio);

// after
float ratio = count == 0 ? 0f : total / count;
cmd.Parameters.AddWithValue("@r", ratio);
Defensive patterns

Strategy: type-guard

Validate before calling

float SafeFloat(float v) => float.IsFinite(v) ? v : throw new ArgumentOutOfRangeException(nameof(v), "non-finite float");

Type guard

static bool IsBindableFloat(float value) => float.IsFinite(value);

Try / catch

try { cmd.Parameters.AddWithValue("@v", v); } catch (ArgumentException) when (v is float f && !float.IsFinite(f)) { cmd.Parameters.AddWithValue("@v", DBNull.Value); }

Prevention

When it happens

Trigger: Passing float.NaN, float.PositiveInfinity, or float.NegativeInfinity as a command parameter, e.g. cmd.Parameters.AddWithValue("@v", float.NaN) followed by ExecuteAsync. Also triggered when a float is boxed as object and reaches the pattern match in the float case.

Common situations: Aggregating sensor/financial data with gaps that become NaN (0f/0f, missing readings), parsing external JSON that yields NaN, or porting code from System.Data.SQLite which historically coerced NaN to NULL instead of throwing.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/a6475200ced79421. Report an issue: GitHub.