{"record":{"id":"896f48482fa9c514","repo":"tursodatabase/turso","slug":"batch-response-is-missing-the-result-for-statement","errorCode":null,"errorMessage":"batch response is missing the result for statement {i}","messagePattern":"batch response is missing the result for statement (.+?)","errorType":"error_code","errorClass":"ProtocolError","httpStatus":null,"severity":"error","filePath":"serverless/python/turso_serverless/connection.py","lineNumber":401,"sourceCode":"        # at the errors, so a failure can still report what completed.\n        results: list[BatchResult | None] = [\n            Connection._decode_batch_statement_result(step_results[offset + i], sql)\n            for i, (sql, _parameters) in enumerate(stmts)\n        ]\n        rollback_error = None\n        if commit_index is not None and step_errors[commit_index + 1] is not None:\n            rollback_error = _classify_error(_server_error(step_errors[commit_index + 1]))\n        try:\n            Connection._raise_batch_step_error(step_errors, len(stmts), offset, commit_index, results)\n        except Exception as primary_error:\n            if rollback_error is not None:\n                primary_error.rollback_error = rollback_error\n            raise\n        if rollback_error is not None:\n            raise rollback_error\n        for i, result in enumerate(results):\n            if result is None:\n                raise ProtocolError(f\"batch response is missing the result for statement {i}\")\n        return results\n\n    @staticmethod\n    def _decode_batch_statement_result(step_result: Any, sql: str) -> BatchResult | None:\n        \"\"\"Decode one statement result of a batch response (section 8.4),\n        or None when the statement did not complete.\"\"\"\n        if not isinstance(step_result, dict):\n            return None\n        columns = [c.get(\"name\") or \"\" for c in step_result.get(\"cols\") or []]\n        rows = [tuple(decode_value(v) for v in row) for row in step_result.get(\"rows\") or []]\n        if columns:\n            description = tuple((name, None, None, None, None, None, None) for name in columns)\n            rowcount = -1\n        else:\n            description = None\n            rowcount = step_result.get(\"affected_row_count\") or 0\n        lastrowid = None\n        raw_rowid = step_result.get(\"last_insert_rowid\")","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/serverless/python/turso_serverless/connection.py#L383-L419","documentation":"After decoding a batch response, every statement must have produced either a result or a recorded error; _decode_batch_result raises ProtocolError if any decoded per-statement result is None (the statement never completed). This catches server replies that silently omit a step's outcome, leaving the batch's final state ambiguous.","triggerScenarios":"A batch response where one statement's decoded result decodes to None (e.g. step_result payload lacks the expected fields after a failed/incomplete step that wasn't captured in step_errors), typically after protocol drift or an interrupted server-side batch.","commonSituations":"Client/server version mismatch, proxy interference dropping JSON fields, and server bugs on partially failed batches where completion status isn't reported.","solutions":["Check step_errors for the failing statement index first — a step error may explain the missing result.","Upgrade client SDK and server to matching versions to rule out protocol drift.","Retry the batch; treat the database state as unknown and make statements idempotent where possible.","Capture the full response and report to Turso if reproducible on current versions."],"exampleFix":"# before\nresults = conn.batch(stmts)  # ProtocolError: missing result for statement 2\n# after\ntry:\n    results = conn.batch(stmts)\nexcept ProtocolError as e:\n    logger.warning(\"batch incomplete: %s — retrying idempotent batch\", e)\n    results = conn.batch(stmts)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    results = conn.batch(stmts)\nexcept ProtocolError as e:\n    log.warning(\"batch incomplete: %s — DB state unknown, retrying idempotent batch\", e)\n    results = conn.batch(stmts)","preventionTips":["Make batched statements idempotent so a retry after an incomplete batch is safe.","Keep SDK and server versions in sync.","Check step_errors content when a batch partially fails.","Bypass intermediaries when diagnosing missing per-step outcomes."],"tags":["python","protocol","server-response","batch","serverless"],"backgroundTag":"malformed-server-response","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-31T11:17:35.598Z","contentChangedAt":"2026-08-31T11:17:35.598Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}