tursodatabase/turso · error · ProtocolError

batch response does not have one result and one error per st

Error message

batch response does not have one result and one error per step: {result}

What it means

When decoding a batch response from the server, the SDK expects the response to carry step_results and step_errors arrays with exactly one entry per submitted statement. If either array is missing, not a list, or has a different length than the number of steps, _decode_batch_result raises ProtocolError — the server response violates the expected protocol (section 8.4) and cannot be trusted.

Source

Thrown at serverless/python/turso_serverless/connection.py:379

        result: dict,
        stmts: list[tuple[str, Any]],
        offset: int,
        commit_index: int | None,
        total_steps: int,
    ) -> list[BatchResult]:
        """Decode a wire-level batch result into per-statement results, or
        raise the error of the step that failed. Failures of the synthetic
        BEGIN/COMMIT steps surface as-is. A ROLLBACK failure is attached to
        that primary error as `rollback_error`."""
        step_results = result.get("step_results")
        step_errors = result.get("step_errors")
        if (
            not isinstance(step_results, list)
            or not isinstance(step_errors, list)
            or len(step_results) != total_steps
            or len(step_errors) != total_steps
        ):
            raise ProtocolError(
                f"batch response does not have one result and one error per step: {result}"
            )
        # Decode the results of the statements that executed before looking
        # at the errors, so a failure can still report what completed.
        results: list[BatchResult | None] = [
            Connection._decode_batch_statement_result(step_results[offset + i], sql)
            for i, (sql, _parameters) in enumerate(stmts)
        ]
        rollback_error = None
        if commit_index is not None and step_errors[commit_index + 1] is not None:
            rollback_error = _classify_error(_server_error(step_errors[commit_index + 1]))
        try:
            Connection._raise_batch_step_error(step_errors, len(stmts), offset, commit_index, results)
        except Exception as primary_error:
            if rollback_error is not None:
                primary_error.rollback_error = rollback_error
            raise
        if rollback_error is not None:

View on GitHub (pinned to c1e5928725)

Solutions

  1. Upgrade the turso_serverless SDK and server together so protocol versions match.
  2. Print the full response object in the message and check whether step_results/step_errors exist at all (indicates talking to the wrong endpoint/server).
  3. Retry the batch — if a proxy corrupted the response, a fresh request may succeed.
  4. Reduce batch size to rule out size-related server truncation.
  5. Report to Turso support with the raw response if a current SDK against a current server still produces it.

Example fix

# before
results = conn.batch(stmts)  # ProtocolError on shape mismatch
# after
try:
    results = conn.batch(stmts)
except ProtocolError as e:
    logger.error("malformed batch response: %s", e)
    results = retry_batch(stmts)  # or surface a clear client/server version mismatch
Defensive patterns

Strategy: retry

Validate before calling

def batch_response_well_formed(result: dict, total_steps: int) -> bool:
    sr, se = result.get("step_results"), result.get("step_errors")
    return (
        isinstance(sr, list) and isinstance(se, list)
        and len(sr) == total_steps and len(se) == total_steps
    )

Try / catch

try:
    results = conn.batch(stmts)
except ProtocolError as e:
    log.error("malformed batch response: %s", e)
    results = conn.batch(stmts)  # retry once; persistent failure => version mismatch

Prevention

When it happens

Trigger: A server (or proxy) returns a batch reply whose step_results/step_errors are absent, truncated, or longer than the submitted steps — e.g. after a server upgrade, a gateway mangling the JSON, or a genuine server bug.

Common situations: Version mismatch between client SDK and server pipeline protocol, responses through caching/transforming proxies, hitting a non-Turso endpoint that echoes unexpected JSON, or server-side truncation on very large batches.

Related errors


AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31). Data as JSON: /api/errors/10543fa2b2586e9f. Report an issue: GitHub.