{"record":{"id":"3890510ffdb12957","repo":"affaan-m/ECC","slug":"agent-profile-inheritance-cycle","errorCode":null,"errorMessage":"agent profile inheritance cycle: {}","messagePattern":"agent profile inheritance cycle: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/config/mod.rs","lineNumber":473,"sourceCode":"        }\n\n        Ok(ResolvedOrchestrationTemplate {\n            template_name: name.to_string(),\n            description,\n            project,\n            task_group,\n            steps,\n        })\n    }\n\n    fn resolve_agent_profile_inner(\n        &self,\n        name: &str,\n        chain: &mut Vec<String>,\n    ) -> Result<ResolvedAgentProfile> {\n        if chain.iter().any(|existing| existing == name) {\n            chain.push(name.to_string());\n            anyhow::bail!(\"agent profile inheritance cycle: {}\", chain.join(\" -> \"));\n        }\n\n        let profile = self\n            .agent_profiles\n            .get(name)\n            .ok_or_else(|| anyhow::anyhow!(\"Unknown agent profile: {name}\"))?;\n\n        chain.push(name.to_string());\n        let mut resolved = if let Some(parent) = profile.inherits.as_deref() {\n            self.resolve_agent_profile_inner(parent, chain)?\n        } else {\n            ResolvedAgentProfile::default()\n        };\n        chain.pop();\n\n        resolved.apply(name, profile);\n        Ok(resolved)\n    }","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/config/mod.rs#L455-L491","documentation":"Runtime error from Config::resolve_agent_profile_inner in ecc2/src/config/mod.rs. The method walks the `inherits` chain and keeps a `chain` vec of visited names. If a name already appears in the chain, it is pushed again and the method bails with \"agent profile inheritance cycle: {}\" joined by ' -> '. The full path (e.g. \"a -> b -> a\") is included so the cycle is obvious.","triggerScenarios":"Defining agent profiles where the `inherits` graph has a cycle: profile A inherits B and B inherits A, or any longer loop. Calling resolve_agent_profile on any node in that cycle triggers the guard.","commonSituations":"Refactoring profiles introduced a back-edge; copy-paste of an `inherits` line created a mutual dependency; a profile was redirected to inherit from a child during reorganization; chained inheritance that worked became cyclic after a rename.","solutions":["Read the cycle path printed in the message and break the back-edge in the named profile.","Audit every `inherits =` in the agent_profiles section and ensure the graph is acyclic.","Move shared defaults into a base profile that both children inherit from, rather than chaining siblings.","Re-resolve after the edit to confirm the cycle is gone."],"exampleFix":"# before\n[agent_profiles.base]\ninherits = \"child\"\n\n[agent_profiles.child]\ninherits = \"base\"\n\n# after\n[agent_profiles.base]\n\n[agent_profiles.child]\ninherits = \"base\"","handlingStrategy":"validation","validationCode":"// Static check over the agent_profiles inherits graph before runtime.\nfn inherits_graph_is_acyclic(cfg: &Config) -> Result<()> {\n    let mut color: HashMap<&str, u8> = HashMap::new(); // 0=white,1=gray,2=black\n    fn visit<'a>(cfg: &'a Config, n: &'a str, color: &mut HashMap<&'a str, u8>) -> Result<()> {\n        match color.get(n).copied() {\n            Some(2) => return Ok(()),\n            Some(1) => anyhow::bail!(\"cycle detected at {n}\"),\n            _ => {}\n        }\n        color.insert(n, 1);\n        if let Some(p) = cfg.agent_profile(n).and_then(|p| p.inherits.as_deref()) {\n            visit(cfg, p, color)?;\n        }\n        color.insert(n, 2);\n        Ok(())\n    }\n    for name in cfg.agent_profile_names() { visit(cfg, name, &mut color)?; }\n    Ok(())\n}","typeGuard":"fn profile_inherits_is_acyclic(cfg: &Config, start: &str) -> bool {\n    let mut seen = HashSet::new();\n    let mut cur = Some(start);\n    while let Some(n) = cur {\n        if !seen.insert(n.to_string()) {\n            return false;\n        }\n        cur = cfg.agent_profile(n).and_then(|p| p.inherits.clone()).as_deref();\n    }\n    true\n}","tryCatchPattern":"let profile = cfg.resolve_agent_profile(name).map_err(|e| {\n    if e.to_string().contains(\"inheritance cycle\") {\n        anyhow::anyhow!(\"{e}; remove the back-edge in the inherits chain\")\n    } else {\n        e\n    }\n})?;","preventionTips":["Audit every `inherits =` line when refactoring profiles.","Prefer a single shared base profile that others inherit from.","Add a config test that fails on cyclic inheritance.","Visualize the inherits graph for large profile sets."],"tags":["rust","config","cycle-detection","inheritance"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}