sqlalchemy/alembic · error · NotImplementedError
TODO
Error message
TODO
What it means
Raised as NotImplementedError('TODO') by ApplyBatchImpl.rename_table (batch.py:712-713). Renaming a table inside a batch_alter_table block is not implemented — batch mode is designed to alter the structure of one existing table, and a rename of the surrounding table is not a supported batch operation. The message is a literal placeholder indicating the feature was never built.
Source
Thrown at alembic/operations/batch.py:713
# Operations.implementation_for(alter_column)
return
raise ValueError("No such constraint: '%s'" % const.name)
else:
if isinstance(const, PrimaryKeyConstraint):
for col in const.columns:
self.columns[col.name].primary_key = False
def create_index(self, idx: Index) -> None:
self.new_indexes[idx.name] = idx # type: ignore[index]
def drop_index(self, idx: Index) -> None:
try:
del self.indexes[idx.name] # type: ignore[arg-type]
except KeyError:
raise ValueError("No such index: '%s'" % idx.name)
def rename_table(self, *arg, **kw):
raise NotImplementedError("TODO")
View on GitHub (pinned to 5551b5d35f)
Solutions
- Perform the rename as a top-level op.rename_table('old', 'new') call, outside any batch context.
- If you also need structural changes, do the rename first at top level, then open batch_alter_table against the new name.
- Do not attempt to rename inside batch mode; there is no workaround.
Example fix
// before
with op.batch_alter_table('user') as batch_op:
batch_op.rename_table('user', 'users')
// after
op.rename_table('user', 'users')
with op.batch_alter_table('users') as batch_op:
batch_op.alter_column('email', existing_type=sa.String(255)) Defensive patterns
Strategy: validation
Validate before calling
# Disallow rename_table inside batch context by routing it to the top level.
def safe_op(op_name, *args, **kwargs):
if op_name == 'rename_table':
assert not _inside_batch, 'rename_table must run at top level, not in batch mode'
return getattr(op, op_name)(*args, **kwargs)
op.rename_table('old', 'new') # top-level, never inside batch Type guard
from typing import Literal
NonBatchOp = Literal['rename_table', 'create_table', 'drop_table']
def must_run_top_level(op_name: str) -> bool:
return op_name in ('rename_table', 'create_table', 'drop_table') Prevention
- Always call op.rename_table() outside a batch_alter_table block.
- Do table renames before opening batch_alter_table against the new name.
- Remember batch mode supports alters only, not DDL on the surrounding table.
When it happens
Trigger: Calling batch_op.rename_table('old', 'new') inside a `with op.batch_alter_table(...)` block. The ApplyBatchImpl class simply has no rename_table logic and raises immediately.
Common situations: Developers assume the batch proxy mirrors the full Operations API and try to combine a table rename with column alters in one batch. This is unsupported on all backends, not just SQLite.
Related errors
- Can't drop table in batch mode
- Constraint must have a name
- No such constraint: '%s'
- No such index: '%s'
- No support for ALTER of constraints in SQLite dialect. Pleas
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/7652404870b74ae4.
Report an issue: GitHub.