pola-rs/polars · error · RuntimeError

{result}

Error message

{result}

What it means

SurrealDBCursorProxy._unpack_result_async inspects the first response envelope of a SurrealDB query; if its 'status' field is anything other than 'OK' (e.g. 'ERR'), the server-side failure payload in response['result'] is re-raised as a RuntimeError. So the message text you see is SurrealDB's own error detail (syntax error, missing namespace/database, permissions), not polars wording. This is the async path used when read_database receives a surrealdb.SurrealDB (async) client.

Source

Thrown at py-polars/src/polars/io/database/_cursor_proxies.py:97

    """Cursor proxy for both SurrealDB and AsyncSurrealDB connections."""

    _cached_result: list[dict[str, Any]] | None = None

    def __init__(self, client: Any) -> None:
        surrealdb = import_optional("surrealdb")
        self.is_async = isinstance(client, surrealdb.AsyncSurrealDB)
        self.execute_options: dict[str, Any] = {}
        self.client = client
        self.query: str = None  # type: ignore[assignment]

    @staticmethod
    async def _unpack_result_async(
        result: Coroutine[Any, Any, list[dict[str, Any]]],
    ) -> Coroutine[Any, Any, list[dict[str, Any]]]:
        """Unpack the async query result."""
        response = (await result)[0]
        if response["status"] != "OK":
            raise RuntimeError(response["result"])
        return response["result"]

    @staticmethod
    def _unpack_result(
        result: list[dict[str, Any]],
    ) -> list[dict[str, Any]]:
        """Unpack the query result."""
        response = result[0]
        if response["status"] != "OK":
            raise RuntimeError(response["result"])
        return response["result"]

    def close(self) -> None:
        """Close the cursor."""
        # no-op; never close a user's Surreal session

    def execute(self, query: str, **execute_options: Any) -> Self:
        """Execute a query (n/a: just store query for the fetch* methods)."""

View on GitHub (pinned to df599052da)

Solutions

  1. Run the same query in the SurrealDB shell / Studio to see the full server error and fix the query
  2. Ensure the connection is established and a namespace + database are selected before read_database (await client.connect(); await client.use('ns', 'db'))
  3. Wrap the read in try/except RuntimeError and surface err.args[0] for logging, since the payload carries the actionable server message

Example fix

# before
await client.connect()
df = pl.read_database('SELECT * FROM orders', connection=client)

# after
await client.connect()
await client.use('prod', 'app')
df = pl.read_database('SELECT * FROM orders', connection=client)
Defensive patterns

Strategy: try-catch

Try / catch

try:
    df = pl.read_database(query, connection=async_client)
except RuntimeError as err:
    detail = err.args[0] if err.args else ''
    # SurrealDB payloads arrive here: parse/handle known cases
    if 'was not found' in str(detail):
        raise KeyError(f'table missing: {detail}') from err
    raise

Prevention

When it happens

Trigger: pl.read_database(query='SELECT * FROM missing_table', connection=async_surreal_client) after client.connect(); invalid SurrealQL; querying before USE NS/DB or connect(); insufficient record-level permissions.

Common situations: Async FastAPI/asyncio services reading from SurrealDB; forgetting await client.use(namespace, database); typos in table names; version drift between the surrealdb python driver and server changing response envelopes.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/1e0b70895fb6c560. Report an issue: GitHub.