sqlalchemy/alembic · error · RevisionError
Relative revision %s didn't produce %d migrations
Error message
Relative revision %s didn't produce %d migrations
What it means
Raised by _parse_downgrade_target when the target is a relative downgrade of the form '+n' with no explicit symbol (i.e., 'downgrade to current + n'). Downgrading forward is nonsensical, so the request cannot produce migrations. It is a RevisionError.
Source
Thrown at alembic/script/revision.py:1116
is a string from the command specifying the branch to consider (or
None if no branch given), and target_revision is a Revision object
which the command refers to. target_revisions is None if the command
refers to 'base'. The target may be specified in absolute form, or
relative to :current_revisions.
"""
if target is None:
return None, None
assert isinstance(
target, str
), "Expected downgrade target in string form"
match = _relative_destination.match(target)
if match:
branch_label, symbol, relative = match.groups()
rel_int = int(relative)
if rel_int >= 0:
if symbol is None:
# Downgrading to current + n is not valid.
raise RevisionError(
"Relative revision %s didn't "
"produce %d migrations" % (relative, abs(rel_int))
)
# Find target revision relative to given symbol.
rev = self._walk(
symbol,
rel_int,
branch_label,
no_overwalk=assert_relative_length,
)
if rev is None:
raise RevisionError("Walked too far")
return branch_label, rev
else:
relative_revision = symbol is None
if relative_revision:
# Find target revision relative to current state.
if branch_label:View on GitHub (pinned to 44fb345033)
Solutions
- Use a negative offset for downgrades: 'alembic downgrade -2'.
- Use 'alembic upgrade +2' for forward relative moves.
- Pass an absolute revision id to remove sign ambiguity.
Example fix
# before alembic downgrade +2 # invalid: downgrade cannot go forward # after alembic downgrade -2
Defensive patterns
Strategy: validation
Validate before calling
import re
if re.match(r'\+\d+$', target):
raise ValueError(
'use a negative offset for downgrade, not %r' % target
) Try / catch
from alembic.script.revision import RevisionError
try:
command.downgrade(cfg, target)
except RevisionError as e:
if "didn't produce" in str(e) and target.startswith('+'):
target = target.replace('+', '-', 1) # fix sign, retry as downgrade Prevention
- Use '-' offsets for downgrade and '+' for upgrade.
- Prefer absolute revision ids to avoid sign confusion.
- Validate relative-target signs before issuing commands.
When it happens
Trigger: Issuing 'alembic downgrade +2' (or 'upgrade' target parsed in downgrade context with a positive offset and no symbol). The relative regex matched a '+' form with no leading revision symbol.
Common situations: Confusing upgrade vs downgrade semantics; passing the wrong sign in a downgrade command; tooling that builds relative targets generically.
Related errors
- Walked too far
- Ambiguous walk
- Ambiguous upgrade from multiple current revisions
- Not a valid downgrade target from current heads
- Revision %s is not an ancestor of revision %s
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/58bab4f029351d26.json.
Report an issue: GitHub.