{"record":{"id":"8c63a9fcaeb68b7d","repo":"FuelLabs/sway","slug":"dependency-cycle-detected","errorCode":null,"errorMessage":"dependency cycle detected: {}","messagePattern":"dependency cycle detected: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"forc-pkg/src/pkg.rs","lineNumber":1242,"sourceCode":"        scc.iter()\n            .filter(|path| path.len() > 1)\n            .for_each(|cyclic_path| {\n                // We are sure that there is an element in cyclic_path vec.\n                let starting_node = &graph[*cyclic_path.last().unwrap()];\n\n                // Adding first node of the path\n                path.push_str(&starting_node.name.to_string());\n                path.push_str(\" -> \");\n\n                for (node_index, node) in cyclic_path.iter().enumerate() {\n                    path.push_str(&graph[*node].name.to_string());\n                    if node_index != cyclic_path.len() - 1 {\n                        path.push_str(\" -> \");\n                    }\n                }\n                path.push('\\n');\n            });\n        anyhow!(\"dependency cycle detected: {}\", path)\n    })\n}\n\n/// Given a graph collects ManifestMap while taking in to account that manifest can be a\n/// ManifestFile::Workspace. In the case of a workspace each pkg manifest map is collected and\n/// their added node lists are merged.\nfn graph_to_manifest_map(manifests: &MemberManifestFiles, graph: &Graph) -> Result<ManifestMap> {\n    let mut manifest_map = HashMap::new();\n    for pkg_manifest in manifests.values() {\n        let pkg_name = &pkg_manifest.project.name;\n        manifest_map.extend(pkg_graph_to_manifest_map(manifests, pkg_name, graph)?);\n    }\n    Ok(manifest_map)\n}\n\n/// Given a graph of pinned packages and the project manifest, produce a map containing the\n/// manifest of for every node in the graph.\n///","sourceCodeStart":1224,"sourceCodeEnd":1260,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/forc-pkg/src/pkg.rs#L1224-L1260","documentation":"Computing the compilation order requires a topological sort of the package graph; a cycle makes that impossible and forc reports each cycle as an arrow chain (a -> b -> ... -> a). At least one package transitively depends on itself, so no valid build order exists.","triggerScenarios":"Two path dependencies whose Forc.toml files reference each other; workspace members mutually depending on one another; a contract dependency chain that loops back (A depends on B, B depends on A); a package listing itself as a dependency.","commonSituations":"Extracting shared code into a crate while leaving circular references behind; refactoring workspace members and flipping a dependency direction without removing the old one.","solutions":["Follow the arrow chain in the message to identify the exact packages in the loop.","Break the cycle by removing one direction of the dependency, or move the shared items into a third package that both depend on."],"exampleFix":"# before: a -> b -> a\n# a/Forc.toml: [dependencies] b = { path = \"../b\" }\n# b/Forc.toml: [dependencies] a = { path = \"../a\" }\n\n# after: both depend on c\n# a/Forc.toml: [dependencies] c = { path = \"../c\" }\n# b/Forc.toml: [dependencies] c = { path = \"../c\" }","handlingStrategy":"validation","validationCode":"fn has_cycle(deps: &std::collections::HashMap<String, Vec<String>>, node: &str, seen: &mut std::collections::HashSet<String>, stack: &mut std::collections::HashSet<String>) -> bool {\n    if stack.contains(node) { return true; }\n    if !seen.insert(node.to_string()) { return false; }\n    stack.insert(node.to_string());\n    let cyclic = deps.get(node).map(|cs| cs.iter().any(|c| has_cycle(deps, c, seen, stack))).unwrap_or(false);\n    stack.remove(node);\n    cyclic\n}\n// build 'deps' from each manifest's dependency names, then check every member root","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When extracting shared code, introduce a new bottom-level crate instead of cross-linking two existing ones.","After flipping a dependency direction, grep all Forc.toml files for the reverse edge before building."],"tags":["graph","cycle","dependencies"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}