tursodatabase/turso · error · ProgrammingError
batch mode must be one of {sorted(_BATCH_MODES)} or None, go
Error message
batch mode must be one of {sorted(_BATCH_MODES)} or None, got {mode!r} What it means
In the embedded Python bindings, Connection.batch() accepts an optional mode naming the transaction-control BEGIN statement for the batch. The mode string is looked up in the _BATCH_MODES dict (case-insensitively); if it isn't one of the recognized names, _batch_begin_sql raises a ProgrammingError before any SQL runs. The error text lists the valid modes, so it is purely a client-side argument-validation error.
Source
Thrown at bindings/python/turso/lib.py:226
"concurrent": "BEGIN CONCURRENT",
}
_TRANSACTION_CONTROL_KEYWORDS = {
"BEGIN",
"COMMIT",
"END",
"ROLLBACK",
"SAVEPOINT",
"RELEASE",
}
def _batch_begin_sql(mode: Optional[str]) -> Optional[str]:
if mode is None:
return None
begin_sql = _BATCH_MODES.get(str(mode).lower())
if begin_sql is None:
raise ProgrammingError(
f"batch mode must be one of {sorted(_BATCH_MODES)} or None, got {mode!r}"
)
return begin_sql
def _normalize_batch_statements(
statements: Iterable[Any],
) -> list[tuple[str, Sequence[Any] | Mapping[str, Any]]]:
"""Normalize batch input to (sql, parameters) pairs. Accepts SQL
strings and (sql, parameters) pairs."""
normalized = []
for index, statement in enumerate(statements):
if isinstance(statement, str):
normalized.append((statement, ()))
continue
if (
isinstance(statement, (tuple, list))
and len(statement) == 2View on GitHub (pinned to c1e5928725)
Solutions
- Use exactly one of the modes printed in the message (lowercase-insensitive): e.g. 'deferred', 'immediate', 'exclusive' as supported by _BATCH_MODES, or None for no transaction.
- Normalize before passing: str(mode).strip().lower(), since matching is done on the lowercased string but whitespace/typos still fail.
- If you have a custom enum, pass mode.value rather than the enum object.
- Check the installed version's _BATCH_MODES dict (bindings/python/turso/lib.py) if upgrading — supported modes may differ from docs.
Example fix
# before conn.batch(stmts, mode="BEGIN") # after conn.batch(stmts, mode="deferred") # or mode=None
Defensive patterns
Strategy: validation
Validate before calling
_VALID_MODES = {"deferred", "immediate", "exclusive"} # intersect with _BATCH_MODES for your version
mode = str(mode).strip().lower() if mode is not None else None
assert mode is None or mode in _VALID_MODES, f"bad batch mode: {mode!r}" Type guard
def is_valid_batch_mode(mode: object) -> bool:
from turso.lib import _BATCH_MODES
return mode is None or str(mode).lower() in _BATCH_MODES Try / catch
try:
conn.batch(stmts, mode=mode)
except ProgrammingError as e:
log.warning("bad batch mode %r: %s", mode, e)
conn.batch(stmts, mode=None) # safe fallback: no wrapping transaction Prevention
- Only pass literal mode strings from _BATCH_MODES or None.
- Lowercase/strip any user- or config-supplied mode.
- If wrapping modes in an Enum, pass .value.
- Re-check _BATCH_MODES after SDK upgrades.
When it happens
Trigger: Calling batch(statements, mode=...) with a mode string not in _BATCH_MODES, e.g. mode="BEGIN", mode="transaction", mode="immediate " with stray characters, or passing a non-string type that lowercases to an unknown name.
Common situations: Porting code from another driver whose batch/transaction API uses different mode vocabulary ('deferred'/'immediate'/'exclusive' vs this library's names), typos like 'IMMEDIATE ' or 'write', and passing an enum member whose str() isn't a plain mode name.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- batch statement {index} must be a SQL string or a (sql, para
- batch mode must be one of {sorted(_BATCH_MODES)} or None, go
- batch statement {index} must be a SQL string or a (sql, para
- Expected first argument to be an array of statements
- SQL command cannot be null
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31).
Data as JSON: /api/errors/35b1137e635124a6.
Report an issue: GitHub.