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

  1. Move the unsupported operation outside the batch_alter_table block and use the top-level op object.
  2. 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).
  3. 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

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


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)