{"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":"validation","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/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/config/mod.rs#L455-L491","documentation":"This error is raised while resolving an agent profile's inheritance chain: the profile being resolved already appears in the current chain, meaning A inherits from B which (directly or transitively) inherits back to A. The library detects the loop before it would recurse forever, and the message includes the full cycle path (e.g. `a -> b -> c -> a`) so the offending links are visible. It is a guard against malformed profile inheritance graphs.","triggerScenarios":"Calling profile resolution (`resolve_agent_profile`-style API with a `chain` accumulator) on a name that is already present in `chain`, i.e. the `extends`/`base` references among agent profiles form a directed cycle.","commonSituations":"Hand-editing config where profile X was changed to extend profile Y and Y was simultaneously repointed to extend X; merging config branches where two profiles each adopted the other as a parent; typos where a profile extends itself (`extends = \"itself\"`); renaming a base profile so an old `extends` value now points back into the chain.","solutions":["Break the cycle: edit the config so the inheritance chain is acyclic — the message's path shows exactly which profiles form the loop.","Remove any self-reference where a profile's `extends`/base field names itself.","Rename the base profile referenced in the cycle to a genuinely independent root profile, or inline its values into the child.","Add a startup config lint that runs resolution for every agent profile and fails fast with cycle detection before runtime use."],"exampleFix":"# before (cyclic)\n[agent_profiles.reviewer]\nextends = \"builder\"\n\n[agent_profiles.builder]\nextends = \"reviewer\"   # cycle: reviewer -> builder -> reviewer\n\n# after\n[agent_profiles.reviewer]\nextends = \"builder\"\n\n[agent_profiles.builder]\n# no extends; standalone base profile","handlingStrategy":"validation","validationCode":"fn profile_graph_is_acyclic(profiles: &HashMap<String, AgentProfile>) -> bool {\n    fn visit(n: &str, p: &HashMap<String, AgentProfile>, seen: &mut Vec<String>) -> bool {\n        if seen.contains(&n.to_string()) { return false; }\n        if let Some(pr) = p.get(n) {\n            if let Some(base) = &pr.extends {\n                seen.push(n.to_string());\n                return visit(base, p, seen);\n            }\n        }\n        true\n    }\n    profiles.keys().all(|n| visit(n, profiles, &mut vec![]))\n}","typeGuard":null,"tryCatchPattern":"match config.resolve_agent_profile(name, &mut chain) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"inheritance cycle\") => {\n        eprintln!(\"Fix profile extends chain: {e}\");\n        default_profile()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep inheritance shallow (at most 2 levels) so cycles are easy to spot.","Never point a profile's extends at a profile that transitively extends it; draw the graph when editing.","Run a startup check that resolves every profile once.","Use a naming convention (e.g. `base-*` for leaf profiles) to signal which profiles are safe bases."],"tags":["config","inheritance","cycle-detection","rust"],"backgroundTag":"invalid-state-transition","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}