{"record":{"id":"5644d9479348aa78","repo":"tursodatabase/turso","slug":"infinite-float-values-cannot-be-sent-over-the-prot","errorCode":null,"errorMessage":"infinite float values cannot be sent over the protocol","messagePattern":"infinite float values cannot be sent over the protocol","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"bindings/python/turso/lib.py","lineNumber":673,"sourceCode":"        return results\n\n    def _prevalidate_batch_parameters(\n        self, stmts: list[tuple[str, Sequence[Any] | Mapping[str, Any]]]\n    ) -> list[tuple[str, Sequence[Any] | Mapping[str, Any]]]:\n        validator = self._conn.prepare_single(\"SELECT ?\")\n        validated = []\n        try:\n            for index, (sql, parameters) in enumerate(stmts):\n                try:\n                    if isinstance(parameters, Mapping):\n                        copied_parameters: Sequence[Any] | Mapping[str, Any] = dict(parameters)\n                        values = copied_parameters.values()\n                    else:\n                        copied_parameters = Cursor._to_positional_params(parameters)\n                        values = copied_parameters\n                    for value in values:\n                        if isinstance(value, float) and math.isinf(value):\n                            raise ValueError(\n                                \"infinite float values cannot be sent over the protocol\"\n                            )\n                        validator.bind_positional(1, value)\n                except Exception as exc:  # noqa: BLE001\n                    raise _batch_statement_error(index, _map_turso_exception(exc)) from exc\n                validated.append((sql, copied_parameters))\n        finally:\n            validator.finalize()\n        return validated\n\n    def _run_batch_statements(\n        self, stmts: list[tuple[str, Sequence[Any] | Mapping[str, Any]]]\n    ) -> list[BatchResult]:\n        \"\"\"Execute the statements of a batch in order, stopping at the\n        first failure and reporting its index along with the results of\n        the statements that completed.\"\"\"\n        results = []\n        for index, (sql, parameters) in enumerate(stmts):","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/python/turso/lib.py#L655-L691","documentation":"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.","triggerScenarios":"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'),)).","commonSituations":"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.","solutions":["Replace infinite values with None (NULL) or a large finite sentinel before binding.","Sanitize parameters: convert inf to None via a helper applied to the params tuple/dict.","If inf must round-trip, store it as TEXT ('Infinity') or a REAL max value instead.","Catch the error and identify which statement index failed via the wrapped _batch_statement_error, then fix that statement's parameters."],"exampleFix":"# before\ncur.execute_batch = conn.batch([(\"INSERT INTO t VALUES (?)\", (float('inf'),)])\n# after\nparams = [None if isinstance(v, float) and math.isinf(v) else v for v in (float('inf'),)]\nconn.batch([(\"INSERT INTO t VALUES (?)\", tuple(params))])","handlingStrategy":"validation","validationCode":"import math\ndef sanitize(v):\n    if isinstance(v, float) and math.isinf(v):\n        return None  # store NULL instead of inf\n    return v\nparams = tuple(sanitize(v) for v in raw_params)","typeGuard":"import math\ndef is_protocol_safe_float(v: object) -> bool:\n    return not (isinstance(v, float) and math.isinf(v))","tryCatchPattern":"try:\n    conn.batch(stmts)\nexcept ValueError as e:\n    if \"infinite float\" in str(e):\n        stmts = [(sql, tuple(sanitize(v) for v in params)) for sql, params in stmts]\n        conn.batch(stmts)\n    else:\n        raise","preventionTips":["Never use float('inf') as a sentinel value for DB parameters.","Sanitize numpy/computed values that may overflow to inf.","Replace infinity with NULL, TEXT 'Infinity', or a finite max sentinel.","Validate parameters at your API boundary before they reach the driver."],"tags":["python","validation","protocol","parameters","float"],"backgroundTag":"unsupported-parameter-value","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-31T11:17:35.598Z","contentChangedAt":"2026-08-31T11:17:35.598Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}