{"record":{"id":"5f4607b493c058d1","repo":"nikivdev/code","slug":"cycle-detected-while-loading-config-includes-5f4607","errorCode":null,"errorMessage":"cycle detected while loading config includes: {}","messagePattern":"cycle detected while loading config includes: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/discover.rs","lineNumber":315,"sourceCode":"        .cloned()\n        .unwrap_or_else(|| \"root\".to_string());\n    (primary, aliases)\n}\n\nfn push_watched_path(paths: &mut Vec<PathBuf>, path: &Path) {\n    if !paths.iter().any(|existing| existing == path) {\n        paths.push(path.to_path_buf());\n    }\n}\n\nfn load_discovery_config(\n    path: &Path,\n    visited: &mut Vec<PathBuf>,\n    watched_paths: &mut Vec<PathBuf>,\n) -> Result<LoadedDiscoveryConfig> {\n    let canonical = path.canonicalize()?;\n    if visited.contains(&canonical) {\n        anyhow::bail!(\n            \"cycle detected while loading config includes: {}\",\n            path.display()\n        );\n    }\n    visited.push(canonical.clone());\n    push_watched_path(watched_paths, &canonical);\n\n    let contents = fs::read_to_string(&canonical)?;\n    let mut cfg = parse_discovery_config(&canonical, &contents)?;\n\n    let mut project_name = cfg.project_name.take();\n    let mut tasks = cfg.tasks;\n    let mut task_resolution = cfg.task_resolution.take();\n\n    for include in cfg.command_files {\n        let include_path = config::resolve_include_path(&canonical, &include.path);\n        let included = load_discovery_config(&include_path, visited, watched_paths)?;\n        if project_name.is_none() {","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/discover.rs#L297-L333","documentation":"Raised by `load_discovery_config` (src/discover.rs:315) while recursively loading config includes: it canonicalizes each path and, if that canonical path is already in the `visited` list, a cycle exists (e.g. a includes b which includes a). The cycle would otherwise cause infinite recursion, so loading aborts and reports the offending path.","triggerScenarios":"A discovery config include chain that revisits any file: `a.toml` includes `b.toml` which includes `a.toml`, a self-include (`a.toml` includes `a.toml`), or symlinked directories whose canonicalized paths resolve back into an already-visited file.","commonSituations":"Copying an include block into a nested config without removing it from the parent, symlinking a shared config directory back onto itself, or merge tooling duplicating includes.","solutions":["Trace the include chain and remove the include that points back to an already-included file","Break the cycle by extracting shared settings into a common file included once","Replace symlink loops with a single canonical shared config path","The message names the path where the cycle was detected — start pruning there"],"exampleFix":"// before (a.toml)\ninclude = [\"b.toml\"]\n# b.toml\ninclude = [\"a.toml\"]\n// after\n# a.toml\ninclude = [\"b.toml\"]\n# b.toml — remove the back-reference\ninclude = []","handlingStrategy":"validation","validationCode":"fn has_include_cycle(entry: &Path) -> Result<bool> {\n    let mut seen = std::collections::HashSet::new();\n    let mut stack = vec![entry.canonicalize()?];\n    while let Some(p) = stack.pop() {\n        if !seen.insert(p.clone()) { return Ok(true); }\n        for inc in parse_includes(&p)? {\n            stack.push(inc.canonicalize()?);\n        }\n    }\n    Ok(false)\n}\n// call before loading; skip load if it returns Ok(true)","typeGuard":"fn acyclic(entry: &Path) -> bool { has_include_cycle(entry).unwrap_or(false) }","tryCatchPattern":"match load_discovery_config(path, &mut visited, &mut watched) {\n    Err(e) if e.to_string().contains(\"cycle detected while loading config includes\") => {\n        eprintln!(\"fix the include chain at {} and retry\", e.to_string());\n    }\n    other => other?,\n}","preventionTips":["Keep a single shared config included once, never re-included by children","Avoid symlink loops in config directories","After merging config changes, grep includes for back-references","Track visited includes when generating configs programmatically"],"tags":["config","include-cycle","recursion"],"backgroundTag":"config-include-cycle","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}