sqlalchemy/alembic · error · ValueError
No such index: '%s'
Error message
No such index: '%s'
What it means
Raised by ApplyBatchImpl.drop_index() when del self.indexes[idx.name] raises KeyError. The index name supplied to batch_op.drop_index() is not among the indexes reflected/copied from the target table, so batch mode cannot remove it from the rebuild plan.
Source
Thrown at alembic/operations/batch.py:710
# type-bound constraints are only included in the new
# table via their type object in any case, so ignore the
# drop_constraint() that comes here via the
# 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 44fb345033)
Solutions
- Reflect the table's actual indexes and use the real name.
- Verify the index has not already been dropped earlier in this migration or a prior revision.
- Add an existence guard before calling batch_op.drop_index().
Example fix
// before
with op.batch_alter_table('user') as batch_op:
batch_op.drop_index('ix_user_nonexistent') # raises ValueError
// after
from sqlalchemy import inspect
index_names = [i['name'] for i in inspect(op.get_bind()).get_indexes('user')]
with op.batch_alter_table('user') as batch_op:
if 'ix_user_email' in index_names:
batch_op.drop_index('ix_user_email') Defensive patterns
Strategy: validation
Validate before calling
from sqlalchemy import inspect
def index_exists(bind, table, name) -> bool:
return name in {i['name'] for i in inspect(bind).get_indexes(table)} Try / catch
try:
batch_op.drop_index(name)
except ValueError as e:
if 'No such index' in str(e):
pass # already absent
else:
raise Prevention
- Reflect indexes and verify names before dropping in batch mode.
- Guard drops to keep migrations idempotent.
- Check that the index wasn't dropped in a prior revision.
When it happens
Trigger: Inside batch_alter_table, calling batch_op.drop_index('idx_name') where 'idx_name' is not an index on the table; dropping an index already dropped; index name typo or quoting/case mismatch.
Common situations: Migration referencing an index removed in another branch/revision; index named via naming convention in metadata but reflected under a different name; running migrations out of order against a DB whose state doesn't match.
Related errors
- Can't drop table in batch mode
- Constraint must have a name
- No such constraint: '%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/f9b86f2e7261b72b.json.
Report an issue: GitHub.