sqlalchemy/alembic · error · Exception

revision %s not in map

Error message

revision %s not in map

What it means

Raised by add_revision() when called with the private _replace=True flag on a revision id that is not already present in the revision map. add_revision(_replace=True) is the internal 'replace in place' path; it assumes the revision was previously registered, so a missing entry is a programmer/contract error rather than a user-data error. Unlike most errors here it is a bare Exception (not RevisionError).

Source

Thrown at alembic/script/revision.py:434

                    normalized_resolved
                )
            else:
                revision._normalized_resolved_dependencies = ()

    def add_revision(self, revision: Revision, _replace: bool = False) -> None:
        """add a single revision to an existing map.

        This method is for single-revision use cases, it's not
        appropriate for fully populating an entire revision map.

        """
        map_ = self._revision_map
        if not _replace and revision.revision in map_:
            util.warn(
                "Revision %s is present more than once" % revision.revision
            )
        elif _replace and revision.revision not in map_:
            raise Exception("revision %s not in map" % revision.revision)

        map_[revision.revision] = revision

        revisions = [revision]
        self._add_branches(revisions, map_)
        self._map_branch_labels(revisions, map_)
        self._add_depends_on(revisions, map_)

        if revision.is_base:
            self.bases += (revision.revision,)
        if revision._is_real_base:
            self._real_bases += (revision.revision,)

        for downrev in revision._all_down_revisions:
            if downrev not in map_:
                util.warn(
                    "Revision %s referenced from %s is not present"
                    % (downrev, revision)

View on GitHub (pinned to 44fb345033)

Solutions

  1. Do not call add_revision with _replace=True for revisions you have not yet added; add them normally first (default _replace=False).
  2. Verify membership before replacing: guard with 'if rev.revision in revision_map._revision_map' before calling add_revision(rev, _replace=True).
  3. Treat this as an internal API: add_revision is documented as for single-revision use cases; prefer rebuilding the map from the script directory generator for bulk changes.

Example fix

// before
rev_map.add_revision(new_rev, _replace=True)  # raises if not present
// after
if new_rev.revision in rev_map._revision_map:
    rev_map.add_revision(new_rev, _replace=True)
else:
    rev_map.add_revision(new_rev)  # fresh insert
Defensive patterns

Strategy: validation

Validate before calling

# before calling add_revision with _replace=True
if revision.revision not in rev_map._revision_map:
    rev_map.add_revision(revision)            # plain insert
else:
    rev_map.add_revision(revision, _replace=True)

Prevention

When it happens

Trigger: Calling RevisionMap.add_revision(revision, _replace=True) when revision.revision is not a key in the internal _revision_map (the first branch of the if/elif at line 429-434). The non-_replace path only warns on duplicates; only _replace=True raises.

Common situations: Custom ScriptDirectory subclasses or plugins that mutate revisions in place; test harnesses that build a RevisionMap and try to replace a revision that was never added; code that copies a revision map into a fresh map object and forgets to add the originals first.

Related errors


AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04). Data as JSON: /data/errors/251d422061481b85.json. Report an issue: GitHub.