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

  1. Verify the endpoint implements /v3/pipeline and that client/server versions match
  2. Bypass response-mutating intermediaries
  3. 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

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


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