{"record":{"id":"a9c6c86f33477fbe","repo":"sqlalchemy/alembic","slug":"dependency-self-loop-is-detected-in-revisions-s","errorCode":null,"errorMessage":"Dependency self-loop is detected in revisions (%s)","messagePattern":"Dependency self-loop is detected in revisions \\((.+?)\\)","errorType":"exception","errorClass":"DependencyLoopDetected","httpStatus":null,"severity":"error","filePath":"alembic/script/revision.py","lineNumber":1596,"sourceCode":"        if illegal_chars:\n            raise RevisionError(\n                \"Character(s) '%s' not allowed in revision identifier '%s'\"\n                % (\", \".join(sorted(illegal_chars)), revision)\n            )\n\n    def __init__(\n        self,\n        revision: str,\n        down_revision: str | tuple[str, ...] | None,\n        dependencies: str | tuple[str, ...] | None = None,\n        branch_labels: str | tuple[str, ...] | None = None,\n    ) -> None:\n        if down_revision and revision in util.to_tuple(down_revision):\n            raise LoopDetected(revision)\n        elif dependencies is not None and revision in util.to_tuple(\n            dependencies\n        ):\n            raise DependencyLoopDetected(revision)\n\n        self.verify_rev_id(revision)\n        self.revision = revision\n        self.down_revision = tuple_rev_as_scalar(util.to_tuple(down_revision))\n        self.dependencies = tuple_rev_as_scalar(util.to_tuple(dependencies))\n        self._orig_branch_labels = util.to_tuple(branch_labels, default=())\n        self.branch_labels = set(self._orig_branch_labels)\n\n    def __repr__(self) -> str:\n        args = [repr(self.revision), repr(self.down_revision)]\n        if self.dependencies:\n            args.append(\"dependencies=%r\" % (self.dependencies,))\n        if self.branch_labels:\n            args.append(\"branch_labels=%r\" % (self.branch_labels,))\n        return \"%s(%s)\" % (self.__class__.__name__, \", \".join(args))\n\n    def add_nextrev(self, revision: Revision) -> None:\n        self._all_nextrev = self._all_nextrev.union([revision.revision])","sourceCodeStart":1578,"sourceCodeEnd":1614,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/script/revision.py#L1578-L1614","documentation":"Raised as DependencyLoopDetected when a Revision's dependencies list contains its own revision id (revision.py:1593-1596). While down_revision defines the parent chain, dependencies declare cross-branch ordering constraints — a revision cannot depend on itself, as that creates a circular dependency that cannot be topologically sorted.","triggerScenarios":"Constructing a Revision where revision appears in the dependencies tuple. Occurs at revision.py:1593: 'elif dependencies is not None and revision in util.to_tuple(dependencies)'. Triggered by adding a revision's own id to its dependencies= argument.","commonSituations":"Adding dependencies to express cross-branch ordering and accidentally including the current revision id. Copy-pasting a dependency list that already contained the revision. Merge revisions where the revision id was also listed as a dependency for clarity but creates a loop.","solutions":["Inspect the migration script's dependencies= argument and remove the revision's own id from it.","Dependencies should only reference OTHER revisions that must be applied before this one.","If you need to express that this revision depends on its own down_revision chain, that's already implicit — no dependency entry needed.","Run 'alembic history --verbose' after fixing to confirm no cycles remain."],"exampleFix":"# before\nrevision = 'abc123'\ndown_revision = 'parent789'\ndependencies = ['abc123', 'other456']  # self-dependency!\n\n# after\nrevision = 'abc123'\ndown_revision = 'parent789'\ndependencies = ['other456']","handlingStrategy":"validation","validationCode":"def has_no_dependency_self_loop(revision, dependencies):\n    from alembic.util import to_tuple\n    if dependencies is None:\n        return True\n    return revision not in to_tuple(dependencies)","typeGuard":null,"tryCatchPattern":"from alembic.script.revision import DependencyLoopDetected\n\ntry:\n    script_dir.revision_map.add_revision(my_revision)\nexcept DependencyLoopDetected as e:\n    print(f\"Dependency self-loop: {e.revisions}\")\n    raise","preventionTips":["Dependencies should reference OTHER revisions only, never the current revision.","Review the dependencies= argument when writing cross-branch migrations.","Run 'alembic history --verbose' after adding dependencies to catch issues early."],"tags":["alembic","migrations","revision-graph","dependency-cycle","validation"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}