sqlalchemy/alembic · error · NotImplementedError
The %s method does not apply to a batch table alter operatio
Error message
The %s method does not apply to a batch table alter operation.
What it means
BatchOperations is a narrowed view of Operations scoped to a single table being altered via batch_alter_table. Methods that operate at the schema level (create_table, drop_table, create_index on an unrelated table, etc.) are mapped to _noop, which raises because they are meaningless inside a batch context where the target table is fixed.
Source
Thrown at alembic/operations/base.py:1713
This basically omits the ``table_name`` and ``schema`` parameters
from associated methods, as these are a given when running under batch
mode.
.. seealso::
:meth:`.Operations.batch_alter_table`
Note that as of 0.8, most of the methods on this class are produced
dynamically using the :meth:`.Operations.register_operation`
method.
"""
impl: BatchOperationsImpl
def _noop(self, operation: Any) -> NoReturn:
raise NotImplementedError(
"The %s method does not apply to a batch table alter operation."
% operation
)
if TYPE_CHECKING:
# START STUB FUNCTIONS: batch_op
# ### the following stubs are generated by tools/write_pyi.py ###
# ### do not edit ###
def add_column(
self,
column: Column[Any],
*,
insert_before: str | None = None,
insert_after: str | None = None,
if_not_exists: bool | None = None,
inline_references: bool | None = None,
inline_primary_key: bool | None = None,View on GitHub (pinned to 44fb345033)
Solutions
- Move create_table/drop_table outside the batch_alter_table context and call them on op directly.
- If you need to fully redefine the table, use batch_alter_table(recreate='always') and add columns/constraints via batch_op.add_column / create_*_constraint.
- Check the BatchOperations stub list to see which methods are valid inside batch mode.
Example fix
// before
with op.batch_alter_table('users') as batch_op:
batch_op.create_table(sa.table('extra', sa.column('id', sa.Integer)))
// after
op.create_table('extra', sa.Column('id', sa.Integer))
with op.batch_alter_table('users') as batch_op:
batch_op.add_column(sa.Column('name', sa.String)) Defensive patterns
Strategy: type-guard
Validate before calling
from alembic.operations.base import BatchOperations
if isinstance(op_or_batch, BatchOperations):
raise RuntimeError("Schema-level ops not allowed inside batch_alter_table; call on op instead") Type guard
def is_batch_op(obj) -> bool:
from alembic.operations.base import BatchOperations
return isinstance(obj, BatchOperations) Prevention
- Only call column/constraint/index methods on batch_op; call table-level ops on op.
- Review autogenerated migrations for misplaced create_table inside batch blocks.
- Lint for batch_op.create_table / batch_op.drop_table.
When it happens
Trigger: Inside a 'with op.batch_alter_table("t") as batch_op:' block, calling one of the schema-level methods that are explicitly registered to _noop (commonly batch_op.create_table(...) or batch_op.drop_table(...)).
Common situations: Autogenerated batch block that accidentally included a create_table; a developer assuming batch_op mirrors the full Operations API; copy-pasting an op.create_table call and renaming op to batch_op.
Related errors
- Can't create table in batch mode
- Individual alter column constructs not supported by MySQL
- No support for ALTER of constraints in SQLite dialect. Pleas
- recreate may be one of 'auto', 'always', or 'never'.
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/5c4f638b771b5e16.json.
Report an issue: GitHub.