sqlalchemy/alembic · error · RevisionError
Not a valid downgrade target from current heads
Error message
Not a valid downgrade target from current heads
What it means
Raised by _collect_downgrade_revisions when a branch-scoped downgrade leaves zero root revisions after filtering candidates by the branch's ancestors. Effectively, the requested downgrade target is not reachable / not valid from the current heads on that branch. It is a RevisionError.
Source
Thrown at alembic/script/revision.py:1380
ancestors = {
rev.revision
for rev in self._get_ancestor_nodes(
[self._resolve_branch(branch_label)],
include_dependencies=False,
)
}
# Intersection gives the root revisions we are trying to
# rollback with the downgrade.
roots = [
is_revision(rev)
for rev in self.get_revisions(
{rev.revision for rev in roots}.intersection(ancestors)
)
]
# Ensure we didn't throw everything away when filtering branches.
if len(roots) == 0:
raise RevisionError(
"Not a valid downgrade target from current heads"
)
heads = self.get_revisions(upper)
# Aim is to drop :branch_revision; to do so we also need to drop its
# descendents and anything dependent on it.
downgrade_revisions = set(
self._get_descendant_nodes(
roots,
include_dependencies=True,
omit_immediate_dependencies=False,
)
)
active_revisions = set(
self._get_ancestor_nodes(heads, include_dependencies=True)
)
View on GitHub (pinned to 44fb345033)
Solutions
- Drop the branch scope and downgrade by absolute revision id.
- Confirm the current heads and the target's lineage with 'alembic history' before downgrading.
- Ensure the branch you name actually contains a current head or a reachable ancestor of one.
Example fix
# before alembic downgrade mybranch@deadbeef # not valid from current heads # after alembic downgrade deadbeef # absolute, unscoped
Defensive patterns
Strategy: validation
Validate before calling
heads = script.get_heads()
branch_rev = script.get_revision('%s@head' % branch_label)
if not script._revision_map._shares_lineage(branch_rev, heads):
raise ValueError(
'branch %s has no current head to downgrade from' % branch_label
) Try / catch
from alembic.script.revision import RevisionError
try:
command.downgrade(cfg, '%s@%s' % (branch_label, target))
except RevisionError as e:
if 'Not a valid downgrade target' in str(e):
command.downgrade(cfg, target) # retry unscoped Prevention
- Verify the branch still has a current head before branch-scoped downgrades.
- Prefer absolute, unscoped revision ids.
- Inspect current heads and lineage before downgrading across branches.
When it happens
Trigger: Issuing a branch-scoped downgrade (e.g., 'alembic downgrade mybranch@<revid>') where the target is not on the current head lineage of mybranch, so after filtering roots the candidate set is empty.
Common situations: Attempting to downgrade a branch whose head has already been merged into / superseded by another branch; branch_label mismatch; targeting a revision that is not an ancestor of any current head on that branch.
Related errors
- Revision %s is not a member of branch '%s'
- No such branch: '%s'
- Relative revision %s didn't produce %d migrations
- Walked too far
- Revision %s is not an ancestor of revision %s
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/b6dcfd3caf38154c.json.
Report an issue: GitHub.