sqlalchemy/alembic · error · RangeNotAncestorError
Revision %s is not an ancestor of revision %s
Error message
Revision %s is not an ancestor of revision %s
What it means
Raised as RangeNotAncestorError inside _collect_downgrade_revisions (revision.py:1415) when a downgrade target revision set has an empty intersection with the currently active revisions. The message template 'Revision %s is not an ancestor of revision %s' is produced by RangeNotAncestorError.__init__; here the lower slot is the literal 'Nothing to drop'. It signals that the revisions you asked to downgrade away from are not actually present in the migration path leading to the requested heads.
Source
Thrown at alembic/script/revision.py:1415
)
# Emit revisions to drop in reverse topological sorted order.
downgrade_revisions.intersection_update(active_revisions)
if implicit_base:
# Wind other branches back to base.
downgrade_revisions.update(
active_revisions.difference(self._get_ancestor_nodes(roots))
)
if (
target_revision is not None
and not downgrade_revisions
and target_revision not in heads
):
# Empty intersection: target revs are not present.
raise RangeNotAncestorError("Nothing to drop", upper)
return downgrade_revisions, heads
def _collect_upgrade_revisions(
self,
upper: _RevisionIdentifierType,
lower: _RevisionIdentifierType,
inclusive: bool,
implicit_base: bool,
assert_relative_length: bool,
) -> tuple[set[Revision], tuple[Revision, ...]]:
"""
Compute the set of required revisions specified by :upper, and the
current set of active revisions specified by :lower. Find the
difference between the two to compute the required upgrades.
:inclusive=True includes the current/lower revisions in the set
View on GitHub (pinned to 44fb345033)
Solutions
- Run `alembic history --verbose` and confirm both the current DB revision (`alembic current`) and the target revision are on the same branch line.
- Ensure the downgrade target is a genuine ancestor of the current head you are rolling back from.
- If branches are involved, disambiguate with the branch label (e.g. branchname@revision) so the correct lineage is selected.
- If migration files were rebased/renamed, align the database alembic_version row with the actual revision id before retrying.
Example fix
# before: target 'abc123' is on a sibling branch, not an ancestor of current head alembic downgrade abc123 # after: downgrade along the correct branch lineage alembic downgrade branchname@abc123
Defensive patterns
Strategy: validation
Validate before calling
from alembic.script import ScriptDirectory
from alembic.script.revision import RangeNotAncestorError
sd = ScriptDirectory.from_config(cfg)
current = sd.get_heads() # or the DB's current revision
target = 'abc123'
rev_map = sd.get_revision_map()
ancestors = set(r.revision for r in rev_map._get_ancestor_nodes([rev_map.get_revision(target)]))
if not any(c in ancestors for c in current):
raise SystemExit(f'{target} is not an ancestor-descendant of current {current}') Try / catch
from alembic.script.revision import RangeNotAncestorError
try:
command.downgrade(cfg, target)
except RangeNotAncestorError as e:
print(f'Cannot downgrade: {e}. Verify branch lineage with `alembic history`.')
# optionally fall back to stamp or resolve branches Prevention
- Always confirm `alembic current` matches a revision on the intended branch before downgrading.
- Use branch-qualified targets (branchname@rev) in multi-branch histories.
- Avoid hand-editing the alembic_version table; use `alembic stamp`.
When it happens
Trigger: Calling command.downgrade (or ScriptDirectory.run_downgrade) with an upper/current set that does not contain the downgrade target, or invoking _collect_downgrade_revisions directly with mismatched upper/lower identifiers. Also triggered when a branch_label filter leaves zero roots while a specific target was requested.
Common situations: Manually editing alembic_version in the DB to a revision not in the current branch; pointing downgrade at a revision id that only exists in a sibling branch; stale migration history after a rebase of migration files; passing a relative specifier like '-1' or 'branch@head' that resolves to nothing on the active path.
Related errors
- Self-loop is detected in revisions (%s)
- Dependency self-loop is detected in revisions (%s)
- Relative revision %s didn't produce %d migrations
- Walked too far
- Not a valid downgrade target from current heads
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/63469407ef96bdb4.json.
Report an issue: GitHub.