tursodatabase/turso · error · ProgrammingError
no SQL statements to execute
Error message
no SQL statements to execute
What it means
Connection._prepare_first calls the native prepare_first, which returns None when the SQL string contains no statement — only whitespace and/or comments. In that case the wrapper raises DB-API ProgrammingError("no SQL statements to execute") instead of silently doing nothing, so empty SQL is surfaced as a bug in the caller.
Source
Thrown at bindings/python/turso/lib.py:331
"""
try:
stmt = self._conn.prepare_single(sql)
_run_execute_with_io(stmt, self.extra_io)
# finalize to ensure completion; finalize never mixes with execute
stmt.finalize()
except Exception as exc: # noqa: BLE001
raise _map_turso_exception(exc)
def _prepare_first(self, sql: str) -> _Prepared:
"""
Prepare the first statement in the given SQL string and return metadata.
"""
try:
opt = self._conn.prepare_first(sql)
except Exception as exc: # noqa: BLE001
raise _map_turso_exception(exc)
if opt is None:
raise ProgrammingError("no SQL statements to execute")
stmt, tail_idx = opt
# Determine whether statement returns columns (rows)
try:
columns = tuple(stmt.columns())
except Exception as exc: # noqa: BLE001
# Clean up statement before re-raising
try:
stmt.finalize()
except Exception:
pass
raise _map_turso_exception(exc)
has_cols = len(columns) > 0
return _Prepared(stmt=stmt, tail_index=tail_idx, has_columns=has_cols, column_names=columns)
def _raise_if_multiple_statements(self, sql: str, tail_index: int) -> None:
"""
Ensure there is no second statement after the first one; otherwise raise ProgrammingError.View on GitHub (pinned to bad083fafb)
Solutions
- Guard before executing: skip when the stripped SQL is empty or contains only comments
- Log the exact SQL string when this fires so the builder bug is obvious
- Fix the builder so it always produces at least one real statement, or make the empty case an explicit no-op in your own code
Example fix
# before
sql = build_query(filters) # may return ""
cur.execute(sql) # ProgrammingError: no SQL statements to execute
# after
sql = build_query(filters)
if sql.strip():
cur.execute(sql) Defensive patterns
Strategy: validation
Validate before calling
import re
def has_statement(sql: str) -> bool:
"""True if sql contains at least one real statement (not only whitespace/comments)."""
no_line = re.sub(r"--[^\n]*", "", sql)
no_block = re.sub(r"/\*.*?\*/", "", no_block, flags=re.S)
return bool(no_block.strip())
if has_statement(sql):
cur.execute(sql) Try / catch
try:
cur.execute(sql)
except ProgrammingError as e:
if str(e) == "no SQL statements to execute":
logger.warning("empty SQL produced by builder: %r", sql)
return []
raise Prevention
- Unit-test SQL builders with the empty-filter case and assert they either emit a statement or signal no-op
- Log the exact SQL on this error — it always indicates a builder/config bug
- Treat comment-only strings as no-ops explicitly in your own layer
When it happens
Trigger: `cur.execute("")`, `cur.execute(" ")`, `cur.execute("-- only a comment")`, `cur.execute("/* nothing */")`, or execute() of dynamically built SQL whose fragments concatenated to an empty/comment-only string.
Common situations: SQL builder/template code that conditionally appends clauses and ends up empty; input filtering that strips every clause; leftover debug placeholders; config-driven SQL where the config omitted the statement.
Related errors
- You can only execute one statement at a time
- autocommit must be True, False, or 'LEGACY'
- executemany() requires a single DML statement
- autocommit must be True, False, or 'LEGACY'
- query timeout must be non-negative
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/b6e46f130515f032.
Report an issue: GitHub.