tursodatabase/turso · error · ProtocolError
expected batch result in pipeline response, got {response}
Error message
expected batch result in pipeline response, got {response} What it means
Session.execute_batch sends a batch step through the pipeline and expects the reply entry to be type="batch" with a dict-shaped result. If the response entry has any other type or a missing/non-dict result, execute_batch raises ProtocolError — the server answered, but not with a batch result this client can decode.
Source
Thrown at serverless/python/turso_serverless/session.py:330
self._refresh_autocommit()
else:
self._autocommit = decoder.probe_executed
if decoder.step_error is not None:
raise decoder.step_error
return decoder.result
def execute_batch(self, steps: list[dict]) -> dict:
"""Execute a batch request on the pipeline endpoint (section 6.2)
and return its raw result: `step_results` and `step_errors` arrays
with one entry per step. Step failures are reported in those
arrays, not raised here."""
results = self.execute_pipeline([{"type": "batch", "batch": {"steps": steps}}])
result = results[0]
if result.get("type") == "error":
raise _server_error(result.get("error"))
response = result.get("response") or {}
if response.get("type") != "batch" or not isinstance(response.get("result"), dict):
raise ProtocolError(f"expected batch result in pipeline response, got {response}")
return response["result"]
def close(self) -> None:
"""Close the stream (section 6.8). Errors are ignored: the stream
may already have expired."""
if self._baton is not None:
try:
self.execute_pipeline([{"type": "close"}], track_autocommit=False)
except Exception:
pass
self._reset_stream()
View on GitHub (pinned to c1e5928725)
Solutions
- Align SDK and server versions; the batch response shape (section 6.2/8.4) changed across protocol revisions.
- Log the full `response` object embedded in the message to see what the server actually returned.
- Bypass proxies/gateways to rule out response rewriting.
- Retry the request; if persistent, capture the payload and report to Turso support.
Example fix
# before
result = session.execute_batch(steps) # ProtocolError: got {'type': 'ok'}
# after
try:
result = session.execute_batch(steps)
except ProtocolError as e:
logger.error("unexpected pipeline reply: %s", e)
raise RuntimeError("server protocol mismatch — upgrade turso_serverless and server together") from e Defensive patterns
Strategy: try-catch
Validate before calling
def batch_reply_well_formed(entry: dict) -> bool:
resp = entry.get("response") or {}
return entry.get("type") != "error" and resp.get("type") == "batch" and isinstance(resp.get("result"), dict) Try / catch
try:
result = session.execute_batch(steps)
except ProtocolError as e:
log.error("unexpected pipeline reply: %s", e)
raise RuntimeError("client/server pipeline protocol mismatch") from e Prevention
- Upgrade turso_serverless SDK and the server together.
- Log the full response embedded in the error for diagnosis.
- Bypass proxies when verifying protocol behavior.
- Ensure you are calling the correct pipeline endpoint revision (/v3/pipeline).
When it happens
Trigger: Calling execute_batch against a server whose pipeline reply for the batch step is an unexpected shape (empty response object, different type tag), after server upgrades/downgrades, or when the response was altered in transit.
Common situations: Client/server protocol version mismatch, load balancers or proxies rewriting responses, and pointing the SDK at an endpoint that speaks a different pipeline revision.
Related errors
- batch response does not have one result and one error per st
- batch response is missing the result for statement {i}
- invalid rowid in server response: {e}
- invalid value in server response: {e}
- unsupported value type in server response: {typ!r}
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31).
Data as JSON: /api/errors/41cd08bbebe66f16.
Report an issue: GitHub.