{"record":{"id":"ee928da03a2483b8","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":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"serverless/python/turso_serverless/protocol.py","lineNumber":44,"sourceCode":"class ProtocolError(RuntimeError):\n    \"\"\"A transport failure or a response that violates the protocol.\"\"\"\n\n\ndef encode_value(value: Any) -> dict:\n    \"\"\"Encode a Python value to a protocol value (section 8).\"\"\"\n    if value is None:\n        return {\"type\": \"null\"}\n    if isinstance(value, bool):\n        return {\"type\": \"integer\", \"value\": str(int(value))}\n    if isinstance(value, int):\n        return {\"type\": \"integer\", \"value\": str(value)}\n    if isinstance(value, float):\n        # The protocol forbids sending non-finite floats (section 8.2).\n        if math.isnan(value):\n            # SQLite binds NaN as NULL; JSON cannot carry it.\n            return {\"type\": \"null\"}\n        if math.isinf(value):\n            raise ValueError(\"infinite float values cannot be sent over the protocol\")\n        return {\"type\": \"float\", \"value\": value}\n    if isinstance(value, str):\n        return {\"type\": \"text\", \"value\": value}\n    if isinstance(value, (bytes, bytearray)):\n        return {\"type\": \"blob\", \"base64\": base64.b64encode(value).decode(\"ascii\")}\n    raise TypeError(f\"Unsupported value type: {type(value).__name__}\")\n\n\ndef decode_value(pv: dict) -> Any:\n    \"\"\"Decode a protocol value (section 8) to a Python value.\"\"\"\n    try:\n        typ = pv[\"type\"]\n        if typ == \"null\":\n            return None\n        if typ == \"integer\":\n            return int(pv[\"value\"])\n        if typ == \"float\":\n            raw = pv[\"value\"]","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/python/turso_serverless/protocol.py#L26-L62","documentation":"ValueError raised by encode_value() (protocol.py:38-44) when a bound parameter is a float equal to +inf or -inf. The SQL-over-HTTP protocol (section 8.2) has no encoding for infinities: JSON cannot carry them (the session even serializes with allow_nan=False), and unlike NaN — which becomes NULL because SQLite itself binds NaN as NULL — infinity is a meaningful REAL value that must not be silently rewritten, so the client refuses to send it.","triggerScenarios":"Binding math.inf / float('inf') / numpy.inf as a positional or named parameter; computed values that overflow (1e308 * 10); data loaded with Python's json module, which by default accepts the non-standard Infinity token and yields inf.","commonSituations":"ETL pipelines ingesting JSON logs containing Infinity; metrics code dividing without a zero guard and storing the result; pandas/numpy workflows converting np.inf to Python float before insert.","solutions":["Check math.isinf(value) before binding and substitute NULL (if the column semantics allow) or reject the row","Fix the upstream math: guard divide-by-zero and overflow before values reach the driver","When ingesting JSON, parse with json.loads(..., parse_constant=lambda c: None) to map Infinity/NaN at the boundary"],"exampleFix":"// before\ncur.execute(\"INSERT INTO metrics(v) VALUES (?)\", (float('inf'),))\n\n// after\nv = float('inf')\ncur.execute(\"INSERT INTO metrics(v) VALUES (?)\", (None if math.isinf(v) else v,))","handlingStrategy":"validation","validationCode":"import math\n\n\ndef sanitize_params(params):\n    \"\"\"The protocol cannot carry infinities; NaN is fine (binds as NULL).\"\"\"\n    out = []\n    for p in params:\n        if isinstance(p, float) and math.isinf(p):\n            raise ValueError(\"infinite float is not representable over the protocol\")\n        out.append(p)\n    return out\n\n\ncur.execute(sql, sanitize_params(params))","typeGuard":"import math\n\n\ndef is_bindable_number(v) -> bool:\n    \"\"\"True when encode_value will accept the float: finite, or NaN (-> NULL).\"\"\"\n    return not isinstance(v, float) or math.isfinite(v) or math.isnan(v)","tryCatchPattern":"import math\n\ntry:\n    cur.execute(sql, params)\nexcept ValueError as e:\n    if \"infinite float\" not in str(e):\n        raise\n    params = tuple(None if isinstance(p, float) and math.isinf(p) else p for p in params)\n    cur.execute(sql, params)","preventionTips":["Validate numeric columns with math.isfinite before insert when data comes from external sources","Parse inbound JSON with json.loads(..., parse_constant=...) to reject or map Infinity at the boundary","Guard division and exponentiation that can overflow to inf upstream of the driver"],"tags":["python","protocol","float","infinity","serialization"],"backgroundTag":"non-finite-float-encoding","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}