{"id":"56f4663aa56c8ab6","repo":"rust-lang/cargo","slug":"cyclic-package-dependency-package-id-depends","errorCode":null,"errorMessage":"cyclic package dependency: package `{id}` depends on itself. Cycle:\n{describe_path}","messagePattern":"cyclic package dependency: package `(.+?)` depends on itself\\. Cycle:\n(.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/resolver/mod.rs","lineNumber":1042,"sourceCode":"        visited: &mut HashSet<PackageId>,\n        path: &mut Vec<PackageId>,\n        checked: &mut HashSet<PackageId>,\n    ) -> CargoResult<()> {\n        if !visited.insert(id) {\n            // We found a cycle and need to construct an error. Performance is no longer top priority.\n            let iter = path.iter().rev().scan(id, |child, parent| {\n                let dep = resolve.transitive_deps_not_replaced(*parent).find_map(\n                    |(dep_id, transitive_dep)| {\n                        (*child == dep_id || Some(*child) == resolve.replacement(dep_id))\n                            .then_some(transitive_dep)\n                    },\n                );\n                *child = *parent;\n                Some((parent, dep))\n            });\n            let iter = std::iter::once((&id, None)).chain(iter);\n            let describe_path = errors::describe_path(iter);\n            anyhow::bail!(\n                \"cyclic package dependency: package `{id}` depends on itself. Cycle:\\n{describe_path}\"\n            );\n        }\n\n        if checked.insert(id) {\n            path.push(id);\n            for (dep_id, _transitive_dep) in resolve.transitive_deps_not_replaced(id) {\n                visit(resolve, dep_id, visited, path, checked)?;\n                if let Some(replace_id) = resolve.replacement(dep_id) {\n                    visit(resolve, replace_id, visited, path, checked)?;\n                }\n            }\n            path.pop();\n        }\n\n        visited.remove(&id);\n        Ok(())\n    }","sourceCodeStart":1024,"sourceCodeEnd":1060,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/resolver/mod.rs#L1024-L1060","documentation":"Detected during post-resolution cycle checking (`visit` traversal in `mod.rs`): a package transitively depends on itself through the resolved graph (including via replacements). Cargo performs a DFS keeping a `visited` set and a `path` stack; revisiting a node already in `visited` means a cycle, which is unsupported because dependency resolution assumes a DAG.","triggerScenarios":"A dependency graph where A → B → A (directly or transitively), including through `[replace]`/`[patch]` substitutions that close a loop. The `!visited.insert(id)` check fires when `visit` re-enters an in-progress node.","commonSituations":"Path/git dependencies that accidentally point back at each other (workspace crates with circular path deps); `[patch]` or `[replace]` that substitutes a package with one depending on the original; dev-dependency cycles between two crates in a workspace; renaming/re-exporting crates that create a loop.","solutions":["Break the cycle: move the shared code into a third crate that both depend on, instead of A↔B.","For dev-dependency cycles, convert one direction to a build-dependency or extract tests into a separate crate.","Audit `[patch]`/`[replace]` entries to ensure a replacement doesn't reintroduce a dependency on the original package.","Run `cargo tree -e features` or inspect the reported `describe_path` to see the exact cycle members."],"exampleFix":"# before: crate-a depends on crate-b (path), crate-b depends on crate-a (path)\n# after: extract shared module into crate-c, both a and b depend on c","handlingStrategy":"validation","validationCode":"# Detect cycles before resolving with cargo tree:\ncargo tree --cycles 2>/dev/null  # exits non-zero / lists cycles if any\n\n# Static check in CI: forbid circular path deps\n# review [dependencies] path = entries for back-references","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep workspace dependency graphs acyclic; extract shared code into a leaf crate.","Run `cargo tree` regularly to spot unexpected edges.","Review `[patch]`/`[replace]` to ensure replacements don't re-introduce the original as a transitive dep."],"tags":["dependency","cycle","graph","workspace"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}