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
- Confirm the URL points at the Turso SQL-over-HTTP endpoint the client supports and that client/server versions match
- Upgrade the turso_serverless package (and the server) to aligned releases
- Remove or bypass intermediaries that rewrite response bodies, then retry on the fresh stream the driver already started
- 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
- Pin client and server to compatible protocol versions in your lockfile/deploy
- Terminate TLS directly to the database; avoid middleboxes that rewrite response bodies
- Log the raw response when this fires — it is evidence of a spec violation worth reporting
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
- invalid cursor response: {e}
- invalid cursor entry: {e}
- invalid rowid in server response: {e}
- invalid pipeline response: {e}
- expected get_autocommit result in pipeline response, got {re
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/64db8054b3f49d75.
Report an issue: GitHub.