{"record":{"id":"ab6809b2f235b294","repo":"tursodatabase/turso","slug":"request-to-url-failed-e-r","errorCode":null,"errorMessage":"request to {url} failed: {e!r}","messagePattern":"request to (.+?) failed: (.+?)","errorType":"exception","errorClass":"ProtocolError","httpStatus":null,"severity":"error","filePath":"serverless/python/turso_serverless/session.py","lineNumber":218,"sourceCode":"                    for key in (\"error\", \"message\"):\n                        if isinstance(parsed.get(key), str):\n                            message = parsed[key]\n                            break\n            except ValueError:\n                pass\n            if message is not None:\n                raise ProtocolError(f\"HTTP status {e.code}: {message}\") from None\n            raise ProtocolError(f\"HTTP status {e.code}\") from None\n        except urllib.error.URLError as e:\n            self._reset_stream()\n            raise ProtocolError(f\"request to {url} failed: {e.reason}\") from None\n        except (http.client.HTTPException, OSError) as e:\n            # Reading the body can fail after urlopen returned, e.g. with\n            # IncompleteRead on a truncated chunked response or a connection\n            # reset; URLError does not cover these, but they are equally\n            # fatal for the stream.\n            self._reset_stream()\n            raise ProtocolError(f\"request to {url} failed: {e!r}\") from None\n\n    def _update_stream(self, baton: Optional[str], base_url: Optional[str]) -> None:\n        self._baton = baton\n        if base_url:\n            self._base_url = normalize_url(base_url)\n\n    def execute_pipeline(self, requests: list[dict], track_autocommit: bool = True) -> list[dict]:\n        \"\"\"Execute a pipeline (section 5). When `track_autocommit` is set, a\n        `get_autocommit` request is appended and its answer refreshes the\n        cached transaction state; the returned results cover only the\n        caller's requests.\"\"\"\n        reqs = list(requests)\n        if track_autocommit:\n            reqs.append({\"type\": \"get_autocommit\"})\n        raw = self._post(\"/v3/pipeline\", {\"baton\": self._baton, \"requests\": reqs})\n        try:\n            resp: dict[str, Any] = json.loads(raw)\n        except ValueError as e:","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/python/turso_serverless/session.py#L200-L236","documentation":"ProtocolError raised by Session._post (session.py:212-218) when the response body could not be read after urlopen returned — http.client.HTTPException (e.g. IncompleteRead on a truncated chunked response) or OSError (connection reset). The code comment notes URLError does not cover these, but they are equally fatal for the stream, which is reset. Unlike error 292, the request connected and headers arrived; the body died mid-transfer.","triggerScenarios":"Server or intermediary closes the connection mid-body on a large streamed result set; proxy idle/read timeout firing during a long /v3/cursor response; flaky networks resetting connections under load.","commonSituations":"Large SELECTs (wide rows, big blobs) exceeding proxy buffer or time budgets; aggressive load-balancer timeouts; mobile or unstable uplinks; serverless function execution limits killing in-flight responses.","solutions":["Retry idempotent reads — the stream was reset, the next statement opens a fresh one","Reduce response size with pagination (LIMIT/OFFSET or keyset) and avoid selecting huge blobs unneeded","Raise read/idle timeouts on any proxy or load balancer between client and database"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import time\nfrom turso_serverless.protocol import ProtocolError\n\ndef fetch_paged(conn, base_sql, page=1000):\n    offset, rows = 0, []\n    while True:\n        try:\n            batch = conn.execute(f\"{base_sql} LIMIT {page} OFFSET {offset}\").fetchall()\n        except ProtocolError as e:\n            if \"IncompleteRead\" not in str(e) and \"HTTPException\" not in str(e):\n                raise\n            page = max(page // 2, 50)  # truncated mid-body: shrink and retry\n            continue\n        rows.extend(batch)\n        if len(batch) < page:\n            return rows\n        offset += page","preventionTips":["Stream large reads in pages (LIMIT/keyset) instead of one giant cursor batch","Avoid selecting huge blob columns you do not need","Tune proxy/LB read timeouts above your worst-case query duration"],"tags":["python","network","truncated-response","connection-reset"],"backgroundTag":"truncated-response","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}