sqlalchemy/alembic · error · NotImplementedError
Can't drop table in batch mode
Error message
Can't drop table in batch mode
What it means
Raised by BatchOperationsImpl.drop_table() when op.drop_table() is invoked inside a with op.batch_alter_table(...) block. Batch mode operates on a single existing table's columns, constraints and indexes; it cannot drop the table under alteration because the whole batch contract is built around recreating one table. The method is a deliberate stub so callers fail fast rather than produce corrupt DDL.
Source
Thrown at alembic/operations/batch.py:201
self.batch.append(("rename_table", arg, kw))
def create_index(self, idx: Index, **kw: Any) -> None:
self.batch.append(("create_index", (idx,), kw))
def drop_index(self, idx: Index, **kw: Any) -> None:
self.batch.append(("drop_index", (idx,), kw))
def create_table_comment(self, table):
self.batch.append(("create_table_comment", (table,), {}))
def drop_table_comment(self, table):
self.batch.append(("drop_table_comment", (table,), {}))
def create_table(self, table):
raise NotImplementedError("Can't create table in batch mode")
def drop_table(self, table):
raise NotImplementedError("Can't drop table in batch mode")
def create_column_comment(self, column):
self.batch.append(("create_column_comment", (column,), {}))
class ApplyBatchImpl:
def __init__(
self,
impl: DefaultImpl,
table: Table,
table_args: tuple,
table_kwargs: dict[str, Any],
reflected: bool,
partial_reordering: tuple = (),
) -> None:
self.impl = impl
self.table = table # this is a Table object
self.table_args = table_argsView on GitHub (pinned to 44fb345033)
Solutions
- Move the op.drop_table('t') call outside / after the with op.batch_alter_table(...) block, using the top-level op object.
- If you genuinely want to remove the table, drop it with op.drop_table('t') in the normal (non-batch) migration context and remove the batch_alter_table block entirely.
- Audit the migration script to confirm no helper function forwards drop_table into the batch context.
Example fix
// before
with op.batch_alter_table('accounts') as batch_op:
batch_op.alter_column('accounts', 'name', type_=sa.String(100))
batch_op.drop_table('accounts') # raises NotImplementedError
// after
with op.batch_alter_table('accounts') as batch_op:
batch_op.alter_column('accounts', 'name', type_=sa.String(100))
op.drop_table('accounts') Defensive patterns
Strategy: validation
Validate before calling
# Guard before entering the batch block: never route drop_table through batch import inspect # simplest: structurally keep drop_table outside batch_alter_table: # instead of batch_op.drop_table, use op.drop_table after the with-block
Type guard
def is_batch_context(op) -> bool:
from alembic.operations.batch import BatchOperationsImpl
return isinstance(op.get_context().impl, BatchOperationsImpl) if hasattr(op, 'get_context') else False Try / catch
try:
batch_op.drop_table('t')
except NotImplementedError:
# fall back to top-level op outside the batch context
op.drop_table('t') Prevention
- Keep table-level DDL (create/drop table) outside batch_alter_table blocks.
- Review any helper that forwards an op list into both normal and batch contexts.
- Treat batch mode as column/constraint/index-only by convention.
When it happens
Trigger: Calling op.drop_table('t') (or batch_op.drop_table('t')) while inside an active op.batch_alter_table('t') context manager. Any code path that routes a drop-table operation through the BatchOperationsImpl, e.g. a generic loop that applies the same op list to both normal and batch contexts.
Common situations: Copy-pasting a drop_table() call into a batch_alter_table block during a refactor; generic migration helpers that assume every Operations method is available on the batch impl; autogenerated code merged incorrectly so a drop_table lands inside the batch block.
Related errors
- Constraint must have a name
- No such constraint: '%s'
- No such index: '%s'
- constraint cannot be produced; original constraint is not pr
- operation is not reversible; original column is not present
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/a1b19f8377947aca.json.
Report an issue: GitHub.