{"id":"0fa89009e1793195","repo":"sqlalchemy/alembic","slug":"dependency-cycle-is-detected-in-revisions-s","errorCode":null,"errorMessage":"Dependency cycle is detected in revisions (%s)","messagePattern":"Dependency cycle is detected in revisions \\((.+?)\\)","errorType":"exception","errorClass":"DependencyCycleDetected","httpStatus":null,"severity":"critical","filePath":"alembic/script/revision.py","lineNumber":294,"sourceCode":"            for rev in self._iterate_related_revisions(\n                lambda r: r._versioned_down_revisions,\n                heads,\n                map_=cast(_RevisionMapType, rev_map),\n            )\n        }.intersection(\n            rev.revision\n            for rev in self._iterate_related_revisions(\n                lambda r: r.nextrev,\n                bases,\n                map_=cast(_RevisionMapType, rev_map),\n            )\n        )\n        deleted_revs = set(rev_map.keys()) - total_space\n        if deleted_revs:\n            raise CycleDetected(sorted(deleted_revs))\n\n        if not _real_heads or not _real_bases:\n            raise DependencyCycleDetected(list(rev_map))\n        total_space = {\n            rev.revision\n            for rev in self._iterate_related_revisions(\n                lambda r: r._all_down_revisions,\n                _real_heads,\n                map_=cast(_RevisionMapType, rev_map),\n            )\n        }.intersection(\n            rev.revision\n            for rev in self._iterate_related_revisions(\n                lambda r: r._all_nextrev,\n                _real_bases,\n                map_=cast(_RevisionMapType, rev_map),\n            )\n        )\n        deleted_revs = set(rev_map.keys()) - total_space\n        if deleted_revs:\n            raise DependencyCycleDetected(sorted(deleted_revs))","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/script/revision.py#L276-L312","documentation":"Raised as DependencyCycleDetected (subclass of CycleDetected) in _detect_cycles() when, after wiring depends_on links, there are no real heads or no real bases (the dependency subgraph has no endpoints). This signals a cycle purely among the depends_on dependencies declared on revisions, independent of the down_revision lineage. The message lists the revisions involved.","triggerScenarios":"Two revisions where revision A lists revision B in depends_on and B lists A in depends_on; a longer depends_on loop (A->B->C->A); a revision depending on itself via depends_on.","commonSituations":"Manually setting depends_on on revisions to enforce ordering and accidentally forming a loop; cross-branch dependencies declared symmetrically; generated depends_on values that reference each other.","solutions":["Audit the depends_on attributes of the listed revisions and break the cycle.","Use 'alembic history' and inspect each revision's depends_on to find the loop edge.","Re-declare depends_on as a strict DAG (no reciprocal dependencies)."],"exampleFix":"// before\n# revision A: depends_on='B'\n# revision B: depends_on='A'  # cycle\n\n// after\n# revision A: depends_on='B'\n# revision B: depends_on=None","handlingStrategy":"validation","validationCode":"def depends_on_acyclic(dep_map):\n    # dep_map: dict revision_id -> tuple of depends_on ids\n    WHITE, GRAY, BLACK = 0, 1, 2\n    color = {r: WHITE for r in dep_map}\n    def visit(node):\n        color[node] = GRAY\n        for dep in (dep_map.get(node) or ()):\n            if color.get(dep) == GRAY:\n                return True\n            if color.get(dep) == WHITE and visit(dep):\n                return True\n        color[node] = BLACK\n        return False\n    return not any(color[r] == WHITE and visit(r) for r in dep_map)","typeGuard":null,"tryCatchPattern":"try:\n    script_dir.get_revision('heads')\nexcept Exception as e:\n    if 'Dependency cycle' in str(e):\n        # audit depends_on edges on listed revisions\n        ...\n    else:\n        raise","preventionTips":["Declare depends_on as a strict DAG (no reciprocal dependencies).","Avoid depending on a revision that already depends on the current one.","Review depends_on values after rebasing branched migrations."],"tags":["alembic","revisions","migration-graph","dependencies","data-integrity"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}