{"record":{"id":"2899da54693e4a66","repo":"sinelaw/fresh","slug":"plugin-dependency-cycle-detected-among-these-plugins-will","errorCode":null,"errorMessage":"Plugin dependency cycle detected among: {}. These plugins will not be loaded.","messagePattern":"Plugin dependency cycle detected among: (.+?)\\. These plugins will not be loaded\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-parser-js/src/lib.rs","lineNumber":273,"sourceCode":"                    }\n                }\n            }\n            // Sort newly ready plugins alphabetically for determinism\n            newly_ready.sort();\n            queue.extend(newly_ready);\n            queue.sort(); // maintain overall alphabetical order among ready nodes\n        }\n    }\n\n    if result.len() != plugin_names.len() {\n        // Some plugins are in a cycle — find them\n        let in_result: HashSet<&str> = result.iter().map(|s| s.as_str()).collect();\n        let cycle_plugins: Vec<String> = plugin_names\n            .iter()\n            .filter(|n| !in_result.contains(n.as_str()))\n            .cloned()\n            .collect();\n        return Err(anyhow!(\n            \"Plugin dependency cycle detected among: {}. These plugins will not be loaded.\",\n            cycle_plugins.join(\", \")\n        ));\n    }\n\n    Ok(result)\n}\n\n/// Module metadata for scoped bundling\n#[derive(Debug, Clone)]\nstruct ModuleMetadata {\n    /// Canonical path to this module\n    path: PathBuf,\n    /// Variable name for this module's exports (e.g., \"__mod_panel_manager\")\n    var_name: String,\n    /// Named imports from other modules\n    imports: Vec<ImportBinding>,\n    /// Named exports from this module","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-parser-js/src/lib.rs#L255-L291","documentation":"After Kahn's algorithm, any plugin not placed into the result must be part of (or reachable only through) a dependency cycle; `topological_sort_plugins` reports those plugin names and refuses to load any of them, since load order cannot be established.","triggerScenarios":"Calling `topological_sort_plugins` where plugin dependencies form a cycle (A→B→A, or a self-dependency A→A), detected by leftover nodes with nonzero in-degree.","commonSituations":"Two plugins each listing the other as a dependency after config edits; a plugin accidentally depending on itself; merging configs that introduced a circular chain.","solutions":["Break the cycle among the listed plugins by removing one dependency edge in config/plugin metadata.","Remove one of the mutually-dependent plugins if the dependency is unnecessary.","If self-dependency, drop the plugin's reference to itself."],"exampleFix":"// before\n{name = \"a\", deps = [\"b\"]}\n{name = \"b\", deps = [\"a\"]}\n// after\n{name = \"a\", deps = [\"b\"]}\n{name = \"b\", deps = []}","handlingStrategy":"validation","validationCode":"// Detect cycles before sorting (simple DFS)\nfn has_cycle(plugins: &[Plugin]) -> bool {\n    fn visit(n: &str, deps: &HashMap<&str, Vec<&str>>, seen: &mut HashSet<&str>, stack: &mut HashSet<&str>) -> bool {\n        if stack.contains(n) { return true; }\n        if !seen.insert(n) { return false; }\n        stack.insert(n);\n        deps.get(n).map_or(false, |ds| ds.iter().any(|d| visit(d, deps, seen, stack)))\n            || { stack.remove(n); false }\n    }\n    let deps: HashMap<&str, Vec<&str>> = plugins.iter().map(|p| (p.name.as_str(), p.deps.iter().map(|s| s.as_str()).collect())).collect();\n    let mut seen = HashSet::new();\n    plugins.iter().any(|p| visit(&p.name, &deps, &mut seen, &mut HashSet::new()))\n}","typeGuard":null,"tryCatchPattern":"match topological_sort_plugins(&plugins) {\n    Err(e) if e.to_string().contains(\"dependency cycle\") => {\n        log::error!(\"cycle: {e}\");\n        Vec::new() // load none, keep editor running\n    }\n    other => other?,\n}","preventionTips":["Run a cycle check in config validation at startup.","Keep dependency graphs one-directional: base plugins never depend on feature plugins.","Add unit tests for each plugin's dependency list."],"tags":["plugins","dependencies","cycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}