tursodatabase/turso · error · ProgrammingError

Cannot operate on a closed connection

Error message

Cannot operate on a closed connection

What it means

In the serverless client, Connection._ensure_open() raises ProgrammingError('Cannot operate on a closed connection') before _execute_stmt sends anything over the HTTP session. close() sets _closed, and every execution path (queries, DML, commit) goes through the same guard, so a closed serverless connection refuses all work locally without a network round trip.

Solutions

  1. Create a fresh Connection (a new session) for further work
  2. Restructure retry loops to reopen the connection before each attempt
  3. Keep all connection usage inside its context-manager block

Example fix

# before
for attempt in range(3):
    try:
        return conn.execute(sql)
    except Exception:
        conn.close()
        # next iteration reuses the closed conn -> ProgrammingError

# after
for attempt in range(3):
    conn = create_connection(url, token)
    try:
        return conn.execute(sql)
    except Exception:
        conn.close()
Defensive patterns

Strategy: try-catch

Try / catch

from turso_serverless.dbapi import ProgrammingError

try:
    rows = conn.execute(sql).fetchall()
except ProgrammingError as e:
    if "closed connection" not in str(e):
        raise
    conn = create_connection(url, token)
    rows = conn.execute(sql).fetchall()

Prevention

When it happens

Trigger: conn.execute(...) after conn.close(); using the connection after its context manager exited (__aexit__/__exit__ calls close); a retry loop that closes the connection on one error and then continues the loop with the same object.

Common situations: Generic retry wrappers that 'clean up' on failure then retry with the dead connection; serverless handlers keeping a module-level connection past its lifetime; cleanup ordering bugs in request scopes.

Related errors


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

Appendix: source

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

    NotSupportedError = NotSupportedError
    Warning = Warning

    def __init__(
        self,
        session: Session,
        *,
        isolation_level: str | None = "DEFERRED",
    ) -> None:
        self._session = session
        self.isolation_level = isolation_level
        self.row_factory: Callable | type[Row] | None = None
        self.text_factory: Any = str
        self._autocommit_mode: object | bool = "LEGACY"
        self._closed = False

    def _ensure_open(self) -> None:
        if self._closed:
            raise ProgrammingError("Cannot operate on a closed connection")

    def _execute_stmt(
        self,
        sql: str,
        params: list | None = None,
        named_params: list[tuple[str, Any]] | None = None,
        want_rows: bool = True,
    ) -> StmtResult:
        self._ensure_open()
        try:
            return self._session.execute_stmt(
                sql, args=params, named_args=named_params, want_rows=want_rows
            )
        except RuntimeError as e:
            raise _classify_error(e) from None

    @property
    def in_transaction(self) -> bool:

View on GitHub (pinned to c1e5928725)