tursodatabase/turso · error · ProtocolError

invalid value in server response: {e}

Error message

invalid value in server response: {e}

What it means

ProtocolError raised by decode_value() (protocol.py:53-75) when a value object inside a server response is malformed: a missing 'type' key (KeyError), a non-dict value (TypeError), or an unparseable integer/float/base64 payload (ValueError). It means the response violated protocol section 8; the original exception detail is embedded in the message. Callers inside execute_stmt treat any ProtocolError as fatal for the stream and reset the baton.

Source

Thrown at serverless/python/turso_serverless/protocol.py:75

        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":
            return pv["value"]
        if typ == "blob":
            # The server may omit base64 padding (section 8).
            b64 = pv["base64"]
            return base64.b64decode(b64 + "=" * (-len(b64) % 4))
    except (KeyError, TypeError, ValueError) as e:
        raise ProtocolError(f"invalid value in server response: {e}") from None
    raise ProtocolError(f"unsupported value type in server response: {typ!r}")


def build_batch_step(
    sql: str,
    args: Optional[list] = None,
    named_args: Optional[list[tuple[str, Any]]] = None,
    want_rows: bool = True,
    condition: Optional[dict] = None,
) -> dict:
    """Build a batch step for a cursor request (section 7)."""
    encoded_args = [encode_value(a) for a in args] if args else []
    encoded_named = (
        [{"name": name, "value": encode_value(val)} for name, val in named_args]
        if named_args
        else []
    )
    step: dict = {

View on GitHub (pinned to bad083fafb)

Solutions

  1. Confirm the URL points at the Turso SQL-over-HTTP endpoint the client supports and that client/server versions match
  2. Upgrade the turso_serverless package (and the server) to aligned releases
  3. Remove or bypass intermediaries that rewrite response bodies, then retry on the fresh stream the driver already started
  4. If it persists, capture the failing response (HTTP logging proxy) and report it as a protocol violation
Defensive patterns

Strategy: try-catch

Try / catch

from turso_serverless.protocol import ProtocolError

try:
    rows = conn.execute(sql).fetchall()
except ProtocolError as e:
    if not str(e).startswith("invalid value in server response"):
        raise
    # stream already reset; a fresh connection rules out client-side state
    conn = connect(URL, auth_token=TOKEN)
    rows = conn.execute(sql).fetchall()  # retry once, then surface

Prevention

When it happens

Trigger: A server or intermediary returns truncated or rewritten JSON in the row payload of a /v3/cursor response; a server version emits value shapes the client does not understand; a middlebox corrupts field names.

Common situations: Version skew between the turso_serverless client and the server; self-hosted or custom proxies on the path; response-mutating service meshes or CDNs; extremely rare memory/network corruption that still yields valid UTF-8.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/64db8054b3f49d75. Report an issue: GitHub.