{"id":"722118700b260aa1","repo":"sqlalchemy/alembic","slug":"ambiguous-walk","errorCode":null,"errorMessage":"Ambiguous walk","messagePattern":"Ambiguous walk","errorType":"exception","errorClass":"RevisionError","httpStatus":null,"severity":"error","filePath":"alembic/script/revision.py","lineNumber":1081,"sourceCode":"            else:\n                # Walk down\n                if initial == \"base\":\n                    children = ()\n                else:\n                    children = self.get_revisions(\n                        self.heads\n                        if initial is None\n                        else initial.down_revision\n                    )\n                    if not children:\n                        children = (\"base\",)\n            if not children:\n                # This will return an invalid result if no_overwalk, otherwise\n                # further steps will stay where we are.\n                ret = None if no_overwalk else initial\n                return ret\n            elif len(children) > 1:\n                raise RevisionError(\"Ambiguous walk\")\n            initial = children[0]\n\n        return initial\n\n    def _parse_downgrade_target(\n        self,\n        current_revisions: _RevisionIdentifierType,\n        target: _RevisionIdentifierType,\n        assert_relative_length: bool,\n    ) -> tuple[str | None, _RevisionOrBase | None]:\n        \"\"\"\n        Parse downgrade command syntax :target to retrieve the target revision\n        and branch label (if any) given the :current_revisions stamp of the\n        database.\n\n        Returns a tuple (branch_label, target_revision) where branch_label\n        is a string from the command specifying the branch to consider (or\n        None if no branch given), and target_revision is a Revision object","sourceCodeStart":1063,"sourceCodeEnd":1099,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/script/revision.py#L1063-L1099","documentation":"Raised by _walk when a relative walk (+n or -n steps) reaches a node with more than one next/previous revision, so the next step is ambiguous. Relative numeric offsets only work along an unambiguous single line; hitting a branch point or merge point makes the destination undefined. It is a RevisionError.","triggerScenarios":"Issuing 'alembic upgrade +2' or 'downgrade -1' when the current position is a branch point with multiple children/parents; using relative offsets across a merge revision.","commonSituations":"Multi-head trees where '-1' from heads is ambiguous; relative downgrades after a merge; automation that assumes a linear history but the repo has branched.","solutions":["Use absolute revision ids or branch-scoped syntax (e.g., 'mybranch@-1') instead of bare relative offsets.","Merge heads to restore a linear single line, then relative offsets become unambiguous.","Specify the explicit target revision rather than a count."],"exampleFix":"# before\nalembic downgrade -1   # branch point -> Ambiguous walk\n# after\nalembic downgrade mybranch@-1   # or an explicit revision id","handlingStrategy":"validation","validationCode":"heads = script.get_heads()\nif len(heads) > 1:\n    raise ValueError(\n        'relative walk is ambiguous with heads: %s; scope a branch' % heads\n    )","typeGuard":null,"tryCatchPattern":"from alembic.script.revision import RevisionError\ntry:\n    command.downgrade(cfg, '%s@-1' % branch)  # scoped, avoids ambiguity\nexcept RevisionError as e:\n    if 'Ambiguous walk' in str(e):\n        # fall back to explicit revision id\n        ...","preventionTips":["Avoid bare relative offsets in branched trees.","Scope relative walks with a branch label.","Merge heads to keep history linear when possible."],"tags":["relative-revision","walk","ambiguous","branching","alembic"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}