tursodatabase/turso · error · ProtocolError

request to {url} failed: {e.reason}

Error message

request to {url} failed: {e.reason}

What it means

ProtocolError raised by Session._post (session.py:209-211) when urllib raises URLError — the request never produced an HTTP response. The reason is embedded (DNS failure, connection refused, TLS certificate verification failure, timeout). The stream is reset before raising, so any open transaction is gone.

Source

Thrown at serverless/python/turso_serverless/session.py:211

        except urllib.error.HTTPError as e:
            raw = e.read().decode("utf-8", errors="replace")
            self._reset_stream()
            message = None
            try:
                parsed = json.loads(raw)
                if isinstance(parsed, dict):
                    for key in ("error", "message"):
                        if isinstance(parsed.get(key), str):
                            message = parsed[key]
                            break
            except ValueError:
                pass
            if message is not None:
                raise ProtocolError(f"HTTP status {e.code}: {message}") from None
            raise ProtocolError(f"HTTP status {e.code}") from None
        except urllib.error.URLError as e:
            self._reset_stream()
            raise ProtocolError(f"request to {url} failed: {e.reason}") from None
        except (http.client.HTTPException, OSError) as e:
            # Reading the body can fail after urlopen returned, e.g. with
            # IncompleteRead on a truncated chunked response or a connection
            # reset; URLError does not cover these, but they are equally
            # fatal for the stream.
            self._reset_stream()
            raise ProtocolError(f"request to {url} failed: {e!r}") from None

    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."""

View on GitHub (pinned to bad083fafb)

Solutions

  1. Test reachability from the same environment: curl -v <database-url>
  2. Fix the runtime's DNS/egress or proxy env vars
  3. For TLS failures, install a CA bundle (certifi) and point the runtime at it
  4. Retry only transient reasons (timeout, reset); fail fast on DNS or certificate errors
Defensive patterns

Strategy: retry

Validate before calling

import socket, urllib.parse


def endpoint_reachable(url: str, timeout: float = 5.0) -> bool:
    """Cheap pre-flight: resolve + TCP connect before starting work."""
    p = urllib.parse.urlparse(url if "://" in url else "https://" + url)
    try:
        socket.setdefaulttimeout(timeout)
        socket.create_connection((p.hostname, p.port or 443), timeout=timeout).close()
        return True
    except OSError:
        return False

Try / catch

import time
from turso_serverless.protocol import ProtocolError

_TRANSIENT = ("timed out", "Connection reset", "temporarily unavailable")

def run(conn, sql, params=()):
    for attempt in range(3):
        try:
            return conn.execute(sql, params).fetchall()
        except ProtocolError as e:
            reason = str(e)
            if "request to" not in reason or not any(t in reason for t in _TRANSIENT):
                raise  # DNS/cert failures are deterministic: fail fast
            time.sleep(0.5 * 2 ** attempt)

Prevention

When it happens

Trigger: Hostname typo or nonexistent database host; DNS resolution failing inside the runtime; firewall or sandbox blocking outbound egress; TLS errors from self-signed certs or missing CA bundles; proxy env vars (http_proxy/https_proxy) misdirecting urllib.

Common situations: Serverless functions (Lambda, Cloud Run jobs) without network egress permissions; local dev behind VPN DNS; containers with an incomplete CA store; corporate proxy variables set in the environment that urllib picks up automatically.

Related errors


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