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

  1. Convert before binding: dt.isoformat() for datetimes, str() for UUID, float(Decimal), int(np.int64)
  2. Serialize structured values (lists/dicts) to a JSON string yourself
  3. 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

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


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)