tursodatabase/turso · error · TypeError
Unsupported value type
Error message
Unsupported value type: {type(value).__name__} What it means
encode_value() serializes one bind parameter for the SQL-over-HTTP protocol. It supports None, bool and int (sent as integers), finite floats, str, and bytes/bytearray (base64). NaN encodes as null because SQLite binds NaN as NULL; infinite floats are rejected with a separate ValueError. Every other Python object falls through to TypeError('Unsupported value type: ...').
Solutions
- Convert before binding: dt.isoformat() for datetimes, str() for UUID, float(Decimal), int(np.int64)
- Serialize structured values (lists/dicts) to a JSON string yourself
- Restrict parameters to None/int/float/str/bytes at your API boundary
Example fix
# before
conn.execute("INSERT INTO events VALUES (?)", [datetime.now()])
# after
conn.execute("INSERT INTO events VALUES (?)", [datetime.now().isoformat()]) Defensive patterns
Strategy: type-guard
Validate before calling
def encode_param(value):
if isinstance(value, (datetime, date)):
return value.isoformat()
if isinstance(value, Decimal):
return float(value)
return value
params = [encode_param(p) for p in params]
conn.execute(sql, params) Type guard
def is_supported_bind_value(v) -> bool:
# None, bool/int, finite float, str, bytes/bytearray are encodable
if isinstance(v, (int, float, str, bytes, bytearray)):
return not (isinstance(v, float) and math.isinf(v))
return v is None Try / catch
try:
conn.execute(sql, params)
except TypeError as e:
if "Unsupported value type" in str(e):
params = [str(p) if not is_supported_bind_value(p) else p for p in params]
conn.execute(sql, params)
else:
raise Prevention
- Convert datetimes, Decimals, UUIDs, and numpy scalars at the edge of your data layer
- Never assume auto-serialization of objects or containers
- Wrap parameter building in one function you can test
When it happens
Trigger: Binding datetime.datetime, date, Decimal, UUID, numpy scalars, lists, dicts, or custom classes as a statement parameter in the serverless client.
Common situations: Passing domain objects without an ORM; pandas/numpy values leaking into parameter lists; monetary Decimal amounts; expecting JSON-style auto-serialization of nested structures.
Related errors
- batch response does not have one result and one error per…
- batch response is missing the result for statement
- Cannot get raw connection from SQLAlchemy connection
- cursor response body ended before the cursor response line
- expected batch result in pipeline response, got
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/bc6f68e76bc2bf4c.
Report an issue: GitHub.
Appendix: source
Thrown at serverless/python/turso_serverless/protocol.py:50
if value is None:
return {"type": "null"}
if isinstance(value, bool):
return {"type": "integer", "value": str(int(value))}
if isinstance(value, int):
return {"type": "integer", "value": str(value)}
if isinstance(value, float):
# The protocol forbids sending non-finite floats (section 8.2).
if math.isnan(value):
# SQLite binds NaN as NULL; JSON cannot carry it.
return {"type": "null"}
if math.isinf(value):
raise ValueError("infinite float values cannot be sent over the protocol")
return {"type": "float", "value": value}
if isinstance(value, str):
return {"type": "text", "value": value}
if isinstance(value, (bytes, bytearray)):
return {"type": "blob", "base64": base64.b64encode(value).decode("ascii")}
raise TypeError(f"Unsupported value type: {type(value).__name__}")
def decode_value(pv: dict) -> Any:
"""Decode a protocol value (section 8) to a Python value."""
try:
typ = pv["type"]
if typ == "null":
return None
if typ == "integer":
return int(pv["value"])
if typ == "float":
raw = pv["value"]
# A null value encodes a non-finite float (section 8.2); the
# spec says to decode it as NaN.
if raw is None:
return math.nan
return float(raw)
if typ == "text":View on GitHub (pinned to 244cde92a7)