pola-rs/polars · error · RuntimeError
cannot return a frame before executing a query
Error message
cannot return a frame before executing a query
What it means
Raised by ConnectionExecutor.to_polars() when self.result is None, meaning no result set exists to convert. The executor requires that .execute(query) has run and produced a fetchable result before a DataFrame can be materialized. Statements that return no rows (DDL/DML like CREATE/INSERT/UPDATE) or calling to_polars() before execute() both leave result unset.
Source
Thrown at py-polars/src/polars/io/database/_executor.py:596
return self
def to_polars(
self,
*,
iter_batches: bool = False,
batch_size: int | None = None,
schema_overrides: SchemaDict | None = None,
infer_schema_length: int | None = N_INFER_DEFAULT,
) -> DataFrame | Iterator[DataFrame]:
"""
Convert the result set to a DataFrame.
Wherever possible we try to return arrow-native data directly; only
fall back to initialising with row-level data if no other option.
"""
if self.result is None:
msg = "cannot return a frame before executing a query"
raise RuntimeError(msg)
can_close = self.can_close_cursor
if defer_cursor_close := (iter_batches and can_close):
self.can_close_cursor = False
for frame_init in (
self._from_arrow, # init from arrow-native data (where support exists)
self._from_rows, # row-wise fallback (sqlalchemy, dbapi2, pyodbc, etc)
):
frame = frame_init(
batch_size=batch_size,
iter_batches=iter_batches,
schema_overrides=schema_overrides,
infer_schema_length=infer_schema_length,
)
if frame is not None:
if defer_cursor_close:View on GitHub (pinned to df599052da)
Solutions
- Only pass queries that return a result set (SELECT / SHOW / EXPLAIN) to read_database; run DDL and DML through the connection's own cursor or engine.execute
- If using ConnectionExecutor directly, always call cx.execute(query) and check cx.result is not None before cx.to_polars(...)
- For row-affecting statements, wrap them in a SELECT that returns rows, or read with 'RETURNING'-style clauses where the backend supports them
Example fix
# before
df = pl.read_database("INSERT INTO t VALUES (1)", connection) # no result set
# after
with connection.cursor() as cur:
cur.execute("INSERT INTO t VALUES (1)")
df = pl.read_database("SELECT * FROM t", connection) Defensive patterns
Strategy: try-catch
Validate before calling
from polars.io.database._executor import ConnectionExecutor
with ConnectionExecutor(conn) as cx:
cx.execute(query=query)
if cx.result is None:
# statement produced no result set; nothing to frame
... Try / catch
try:
df = pl.read_database(sql, conn)
except RuntimeError as e:
if "cannot return a frame" in str(e):
# sql was DDL/DML with no result set — run it via raw cursor instead
with conn.cursor() as cur:
cur.execute(sql)
df = None
else:
raise Prevention
- Only feed SELECT-like statements to read_database; keep DDL/DML on the raw cursor
- Keep a helper that classifies SQL (SELECT vs other) before choosing the read path
- When using ConnectionExecutor directly, always pair execute() with a result check
When it happens
Trigger: Calling pl.read_database() with a non-SELECT statement (e.g. 'CREATE TABLE ...' or an INSERT) on a DBAPI/SQLAlchemy connection; using ConnectionExecutor directly and calling .to_polars() without a prior successful .execute(); executing a query on a cursor whose .fetch*() yields nothing the executor can consume.
Common situations: Scripts that run setup DDL and read-back in one loop through read_database; migrating code from a driver's raw cursor API where execute() alone was harmless; calling read_database on a connection whose dialect/driver returns None from cursor.description.
Related errors
- Unrecognised connection type {qualified_type_name(conn)!r};
- string URI is invalid here; call `read_database_uri` instead
- unable to identify string connection as valid ODBC (no drive
- expected connection to be a URI string; found {qualified_typ
- Event loop stopped before Future completed.
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/3c5a9bde6bd2ed46.
Report an issue: GitHub.