{"record":{"id":"f9b86f2e7261b72b","repo":"sqlalchemy/alembic","slug":"no-such-index-s","errorCode":null,"errorMessage":"No such index: '%s'","messagePattern":"No such index: '(.+?)'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/operations/batch.py","lineNumber":710,"sourceCode":"                # type-bound constraints are only included in the new\n                # table via their type object in any case, so ignore the\n                # drop_constraint() that comes here via the\n                # Operations.implementation_for(alter_column)\n                return\n            raise ValueError(\"No such constraint: '%s'\" % const.name)\n        else:\n            if isinstance(const, PrimaryKeyConstraint):\n                for col in const.columns:\n                    self.columns[col.name].primary_key = False\n\n    def create_index(self, idx: Index) -> None:\n        self.new_indexes[idx.name] = idx  # type: ignore[index]\n\n    def drop_index(self, idx: Index) -> None:\n        try:\n            del self.indexes[idx.name]  # type: ignore[arg-type]\n        except KeyError:\n            raise ValueError(\"No such index: '%s'\" % idx.name)\n\n    def rename_table(self, *arg, **kw):\n        raise NotImplementedError(\"TODO\")\n","sourceCodeStart":692,"sourceCodeEnd":714,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/operations/batch.py#L692-L714","documentation":"Raised as ValueError by ApplyBatchImpl.drop_index (batch.py:706-710) after a KeyError when idx.name is not present in self.indexes (the dict of indexes tracked on the batch-recreated table). Batch mode needs to know which index to omit from the new table, so an unknown index name is an error, not a no-op.","triggerScenarios":"Calling batch_op.drop_index('idx_missing') (or batch_op.drop_index(sa.Index('idx_missing'))) inside a batch_alter_table block where no such index exists on the table. Common with a typo'd index name or an index that belongs to a different table.","commonSituations":"Auto-generated migration references an index name that was renamed/already dropped; index names that differ between dev (SQLite) and prod (Postgres); dropping an index created in the same batch but with a different name string.","solutions":["Confirm the index name via the DB catalog (\\di in psql, PRAGMA index_list in SQLite) and pass the exact name.","If you are creating and immediately dropping an index in one batch, simply omit both calls.","If the drop may not apply in all environments, inspect the batch table's indexes before calling drop_index."],"exampleFix":"// before\nwith op.batch_alter_table('users') as batch_op:\n    batch_op.drop_index('ix_user_email')  # typo / wrong name\n// after\nwith op.batch_alter_table('users') as batch_op:\n    batch_op.drop_index('ix_users_email')  # correct name","handlingStrategy":"validation","validationCode":"# Confirm an index exists before dropping it in batch mode.\ndef index_exists(conn, table, index_name):\n    return conn.exec_driver_sql(\n        \"SELECT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = %s)\",\n        (index_name,),\n    ).scalar()\n\nif index_exists(bind, 'users', 'ix_users_email'):\n    with op.batch_alter_table('users') as batch_op:\n        batch_op.drop_index('ix_users_email')","typeGuard":"def is_known_index(name: str, known: set[str]) -> bool:\n    return name in known","tryCatchPattern":"try:\n    with op.batch_alter_table('users') as batch_op:\n        batch_op.drop_index('maybe_missing')\nexcept ValueError as e:\n    if 'No such index' in str(e):\n        pass  # already absent; idempotent\n    else:\n        raise","preventionTips":["Query the DB catalog (pg_indexes / PRAGMA index_list) for the exact index name first.","Use consistent index names across environments via naming_convention.","Avoid dropping an index you did not confirm exists."],"tags":["alembic","batch-mode","indexes","database-migration"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}