tursodatabase/turso · error · ProtocolError
cursor response body ended before the cursor response line
Error message
cursor response body ended before the cursor response line
What it means
_parse_cursor_body() splits a streamed cursor response (section 7.1) into a first JSON line plus the entry lines that follow. It first strips blank lines; if nothing remains, it raises ProtocolError('cursor response body ended before the cursor response line'). The HTTP layer returned a body, but that body carried no payload at all - the stream ended before any cursor response line appeared.
Solutions
- Retry the request with backoff - an empty body is often transient
- Bypass or reconfigure proxies that truncate streaming responses
- If it reproduces consistently, capture the raw response (status, headers, body length) and report it
Defensive patterns
Strategy: retry
Try / catch
from turso_serverless.protocol import ProtocolError
for attempt in range(3):
try:
result = session.execute_stmt(sql)
break
except ProtocolError as e:
if "ended before the cursor response line" not in str(e) or attempt == 2:
raise
time.sleep(0.5 * (2 ** attempt)) # empty body: usually transient Prevention
- Wrap streaming calls in bounded retry with jitter
- Health-check any proxy in front of the database endpoint
- Log raw body length on decode failures to distinguish empty from truncated
When it happens
Trigger: Server returns an empty 200 body; a proxy or flaky network truncates the streamed response to nothing; code that reads the response body twice and gets an empty second read.
Common situations: Load balancers or CDNs stripping streamed bodies; mobile networks dropping mid-response; server bugs on error paths that still return 200 with no content.
Related errors
- invalid cursor response
- No response body
- batch response does not have one result and one error per…
- batch response is missing the result for statement
- expected batch result in pipeline response, got
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-20).
Data as JSON: /api/errors/a97be9527a76f243.
Report an issue: GitHub.
Appendix: source
Thrown at serverless/python/turso_serverless/session.py:65
class StmtResult:
"""The decoded output of one executed statement."""
columns: list[str]
rows: list[tuple]
affected_rows: int
last_insert_rowid: Optional[int]
# Index of the autocommit probe step appended to every cursor batch.
_PROBE_STEP = 1
def _parse_cursor_body(raw: bytes) -> tuple[dict, list[dict]]:
"""Split a cursor response body (section 7.1) into the cursor response
line and the decoded entries that follow it."""
lines = [line for line in raw.decode("utf-8").splitlines() if line.strip()]
if not lines:
raise ProtocolError("cursor response body ended before the cursor response line")
try:
cursor_resp = json.loads(lines[0])
except ValueError as e:
raise ProtocolError(f"invalid cursor response: {e}") from None
entries = []
for line in lines[1:]:
try:
entries.append(json.loads(line))
except ValueError as e:
raise ProtocolError(f"invalid cursor entry: {e}") from None
return cursor_resp, entries
class _CursorDecoder:
"""Folds streamed cursor entries (section 7.2) into a statement result,
tracking the trailing autocommit probe step separately from the caller's
step."""
View on GitHub (pinned to c1e5928725)