sqlalchemy/alembic · error · NotImplementedError
The method does not apply to a batch table alter operation.
Error message
The %s method does not apply to a batch table alter operation.
What it means
BatchOperations._noop raises NotImplementedError when a top-level Operations method that is meaningless inside batch mode is invoked on the batch operations proxy. Inside a `with op.batch_alter_table('t') as batch_op:` block, only column/constraint/index operations that pertain to the table being altered are valid; operations like create_table, drop_table, create_index at the top level are routed to _noop.
Solutions
- Move the unsupported operation outside the batch_alter_table block and use the top-level op object.
- Verify you are calling batch_op methods that apply to the table being batched (add_column, alter_column, drop_column, create/drop_constraint, create/drop_index).
- For create_table/drop_table, use the non-batch op.create_table outside the with block.
Example fix
# before (wrong)
with op.batch_alter_table('t') as batch_op:
batch_op.create_table('new_t', ...) # _noop error
# after
with op.batch_alter_table('t') as batch_op:
batch_op.alter_column('c', type_=sa.String(50))
op.create_table('new_t', ...) # outside batch Defensive patterns
Strategy: type-guard
Validate before calling
BATCH_ALLOWED = {'add_column','drop_column','alter_column',
'create_constraint','drop_constraint',
'create_index','drop_index',
'create_table_comment','drop_table_comment',
'create_column_comment'}
def batch_call(batch_op, method, *a, **k):
if method not in BATCH_ALLOWED:
raise ValueError(f'{method} is not valid inside batch_alter_table')
getattr(batch_op, method)(*a, **k) Type guard
def is_batch_safe_method(name: str) -> bool:
return name in {'add_column','drop_column','alter_column',
'create_constraint','drop_constraint',
'create_index','drop_index',
'create_table_comment','drop_table_comment',
'create_column_comment'} Prevention
- Only call table-modifying methods on batch_op inside a batch block.
- Use the top-level op object for create_table/drop_table and whole-DB operations.
- Review batch blocks to ensure no stray top-level operations were pasted in.
When it happens
Trigger: Calling batch_op.create_table(...), batch_op.drop_table(...), or another operation wired to _noop inside a batch_alter_table block. Also triggered by methods that only apply to whole-database context, not a single batched table.
Common situations: Copy-pasting top-level op.create_table(...) into a batch block and forgetting to replace op with the non-batch Operations; attempting to create an index on a different table inside a batch context.
Related errors
- Can't create table in batch mode
- No support for ALTER of constraints in SQLite dialect…
- recreate may be one of 'auto', 'always', or 'never'.
- TODO
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/5c4f638b771b5e16.
Report an issue: GitHub.
Appendix: 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 5551b5d35f)