tursodatabase/turso · error · ProgrammingError
autocommit must be True, False, or 'LEGACY'
Error message
autocommit must be True, False, or 'LEGACY'
What it means
The Connection.autocommit setter accepts exactly True, False, or the string "LEGACY" (case-sensitive), mirroring the stdlib sqlite3 autocommit attribute. Any other value raises ProgrammingError before any state changes. Note that 1 and 0 pass because they compare equal to True/False.
Source
Thrown at bindings/python/turso/lib.py:384
raise _map_turso_exception(exc)
@property
def in_transaction(self) -> bool:
try:
return not self._conn.get_auto_commit()
except Exception as exc: # noqa: BLE001
raise _map_turso_exception(exc)
# Provide autocommit property for sqlite3-like API (optional)
@property
def autocommit(self) -> object | bool:
return self._autocommit_mode
@autocommit.setter
def autocommit(self, val: object | bool) -> None:
# Accept True, False, or "LEGACY"
if val not in (True, False, "LEGACY"):
raise ProgrammingError("autocommit must be True, False, or 'LEGACY'")
self._autocommit_mode = val
# If switching to False, ensure a transaction is open
if val is False:
self._ensure_transaction_open()
# If switching to True or LEGACY, nothing else to do immediately.
def close(self) -> None:
# In sqlite3: If autocommit is False, pending transaction is implicitly rolled back.
try:
if self._autocommit_mode is False and self.in_transaction:
try:
self._exec_ddl_only("ROLLBACK")
except Exception:
# As sqlite3 does, ignore rollback failure on close
pass
self._conn.close()
except Exception as exc: # noqa: BLE001
raise _map_turso_exception(exc)View on GitHub (pinned to bad083fafb)
Solutions
- Normalize the incoming value before assigning: map "true"/"1" to True, "false"/"0" to False, "legacy" (any case) to "LEGACY"
- Assign literals directly at the call site: conn.autocommit = True / False / "LEGACY"
- Treat any other value as a configuration error and fail fast with the raw value in the message
Example fix
# before
conn.autocommit = os.environ.get("AUTOCOMMIT", "LEGACY") # "legacy" -> ProgrammingError
# after
modes = {"true": True, "false": False, "legacy": "LEGACY"}
raw = os.environ.get("AUTOCOMMIT", "LEGACY").lower()
if raw not in modes:
raise ValueError(f"invalid AUTOCOMMIT={raw!r}; use true/false/legacy")
conn.autocommit = modes[raw] Defensive patterns
Strategy: validation
Validate before calling
_MODES = {"true": True, "false": False, "legacy": "LEGACY"}
def normalize_autocommit(raw) -> object | bool:
if raw is True or raw is False or raw == "LEGACY":
return raw
key = str(raw).strip().lower()
if key in _MODES:
return _MODES[key]
raise ValueError(f"invalid autocommit value {raw!r}; use True/False/'LEGACY'")
conn.autocommit = normalize_autocommit(config["autocommit"]) Prevention
- Use literals True/False/"LEGACY" (exact case) in code
- Normalize any config/env-sourced value through one helper before assignment
- Watch for config formats that coerce booleans to strings — "true" is not True
When it happens
Trigger: `conn.autocommit = "legacy"` (wrong case), `conn.autocommit = None`, `conn.autocommit = 2`, `conn.autocommit = "on"/"off"` — typically when the mode comes from a config file, environment variable, or JSON/YAML value instead of a literal.
Common situations: Reading the mode from env/config where casing differs; config formats that turn booleans into strings ("true"/"false"); porting isolation_level-style strings ("DEFERRED" etc.) to the autocommit attribute.
Related errors
- autocommit must be True, False, or 'LEGACY'
- retryFetch: attempts must be a finite integer >= 1, got ${at
- Expected first argument to be a function
- Cannot commit in autocommit mode.
- Cannot rollback in autocommit mode.
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/f56f0b2e8b47c6a7.
Report an issue: GitHub.