tursodatabase/turso · error · ValueError

infinite float values cannot be sent over the protocol

Error message

infinite float values cannot be sent over the protocol

What it means

Before running a batch, _prevalidate_batch_parameters scans every parameter value and rejects floats that are +inf or -inf, because the wire protocol has no representation for infinite float values. The check raises a plain ValueError and the batch is wrapped via _batch_statement_error with the failing statement index. NaN and finite floats pass; only infinities are rejected.

Solutions

  1. Replace infinite values with None (NULL) or a large finite sentinel before binding.
  2. Sanitize parameters: convert inf to None via a helper applied to the params tuple/dict.
  3. If inf must round-trip, store it as TEXT ('Infinity') or a REAL max value instead.
  4. Catch the error and identify which statement index failed via the wrapped _batch_statement_error, then fix that statement's parameters.

Example fix

# before
cur.execute_batch = conn.batch([("INSERT INTO t VALUES (?)", (float('inf'),)])
# after
params = [None if isinstance(v, float) and math.isinf(v) else v for v in (float('inf'),)]
conn.batch([("INSERT INTO t VALUES (?)", tuple(params))])
Defensive patterns

Strategy: validation

Validate before calling

import math
def sanitize(v):
    if isinstance(v, float) and math.isinf(v):
        return None  # store NULL instead of inf
    return v
params = tuple(sanitize(v) for v in raw_params)

Type guard

import math
def is_protocol_safe_float(v: object) -> bool:
    return not (isinstance(v, float) and math.isinf(v))

Try / catch

try:
    conn.batch(stmts)
except ValueError as e:
    if "infinite float" in str(e):
        stmts = [(sql, tuple(sanitize(v) for v in params)) for sql, params in stmts]
        conn.batch(stmts)
    else:
        raise

Prevention

When it happens

Trigger: batch() (or the equivalent path in execute) where any positional or named parameter is float('inf'), float('-inf'), or a computed value like 1e400 that evaluates to inf, e.g. ("SELECT ?", (float('inf'),)).

Common situations: Inserting results of numpy computations that overflowed to inf, logging timings where a division by zero produced inf, and defaults like float('inf') used as a sentinel 'unbounded' value being sent to the database.

Related errors


AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31). Data as JSON: /api/errors/5644d9479348aa78. Report an issue: GitHub.

Appendix: source

Thrown at bindings/python/turso/lib.py:673

        return results

    def _prevalidate_batch_parameters(
        self, stmts: list[tuple[str, Sequence[Any] | Mapping[str, Any]]]
    ) -> list[tuple[str, Sequence[Any] | Mapping[str, Any]]]:
        validator = self._conn.prepare_single("SELECT ?")
        validated = []
        try:
            for index, (sql, parameters) in enumerate(stmts):
                try:
                    if isinstance(parameters, Mapping):
                        copied_parameters: Sequence[Any] | Mapping[str, Any] = dict(parameters)
                        values = copied_parameters.values()
                    else:
                        copied_parameters = Cursor._to_positional_params(parameters)
                        values = copied_parameters
                    for value in values:
                        if isinstance(value, float) and math.isinf(value):
                            raise ValueError(
                                "infinite float values cannot be sent over the protocol"
                            )
                        validator.bind_positional(1, value)
                except Exception as exc:  # noqa: BLE001
                    raise _batch_statement_error(index, _map_turso_exception(exc)) from exc
                validated.append((sql, copied_parameters))
        finally:
            validator.finalize()
        return validated

    def _run_batch_statements(
        self, stmts: list[tuple[str, Sequence[Any] | Mapping[str, Any]]]
    ) -> list[BatchResult]:
        """Execute the statements of a batch in order, stopping at the
        first failure and reporting its index along with the results of
        the statements that completed."""
        results = []
        for index, (sql, parameters) in enumerate(stmts):

View on GitHub (pinned to c1e5928725)