tursodatabase/turso · error · ProtocolError
invalid pipeline response: {e}
Error message
invalid pipeline response: {e} What it means
ProtocolError raised by Session.execute_pipeline (session.py:234-238) when the /v3/pipeline response body fails JSON parsing outright. The stream is reset before the error is raised. execute_pipeline backs executescript() and the connection's autocommit tracking, so the error typically surfaces from an executescript call or as a secondary failure while executing statements.
Source
Thrown at serverless/python/turso_serverless/session.py:238
def _update_stream(self, baton: Optional[str], base_url: Optional[str]) -> None:
self._baton = baton
if base_url:
self._base_url = normalize_url(base_url)
def execute_pipeline(self, requests: list[dict], track_autocommit: bool = True) -> list[dict]:
"""Execute a pipeline (section 5). When `track_autocommit` is set, a
`get_autocommit` request is appended and its answer refreshes the
cached transaction state; the returned results cover only the
caller's requests."""
reqs = list(requests)
if track_autocommit:
reqs.append({"type": "get_autocommit"})
raw = self._post("/v3/pipeline", {"baton": self._baton, "requests": reqs})
try:
resp: dict[str, Any] = json.loads(raw)
except ValueError as e:
self._reset_stream()
raise ProtocolError(f"invalid pipeline response: {e}") from None
self._update_stream(resp.get("baton"), resp.get("base_url"))
results = resp.get("results") or []
# The protocol guarantees one result per request (section 5.2); a
# mismatch would misattribute results to the wrong requests.
if len(results) != len(reqs):
raise ProtocolError(
f"pipeline response has {len(results)} results for {len(reqs)} requests"
)
if track_autocommit:
result = results.pop()
if result.get("type") == "error":
raise _server_error(result.get("error"))
response = result.get("response") or {}
if response.get("type") != "get_autocommit" or not isinstance(
response.get("is_autocommit"), bool
):
raise ProtocolError(
f"expected get_autocommit result in pipeline response, got {response}"View on GitHub (pinned to bad083fafb)
Solutions
- Verify the endpoint implements /v3/pipeline and that client/server versions match
- Bypass response-mutating intermediaries
- Retry on the fresh stream the reset created; upgrade the driver if it persists
Defensive patterns
Strategy: try-catch
Try / catch
from turso_serverless.protocol import ProtocolError
try:
conn.executescript(script)
except ProtocolError as e:
if not str(e).startswith("invalid pipeline response"):
raise
conn = connect(URL, auth_token=TOKEN) # stream was reset; reconnect and retry once
conn.executescript(script) Prevention
- Confirm the endpoint implements /v3/pipeline before adding custom infrastructure in front of it
- Keep executescript inputs on the smaller side; very large scripts amplify truncation risk
- Pin client/server versions in deployment manifests
When it happens
Trigger: The pipeline endpoint returns an empty body, an HTML error page, or truncated JSON — same corruption class as errors 287/288 but on /v3/pipeline; also seen when a URL points at a server that does not implement the pipeline endpoint.
Common situations: Intermediaries (gateways, CDNs) rewriting or emptying bodies; version mismatch with a server lacking /v3/pipeline support; network truncation of large script responses.
Related errors
- invalid cursor response: {e}
- expected get_autocommit result in pipeline response, got {re
- invalid value in server response: {e}
- invalid cursor entry: {e}
- invalid rowid in server response: {e}
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/e7cae99a0b85b218.
Report an issue: GitHub.