affaan-m/ECC · error
agent profile inheritance cycle: {}
Error message
agent profile inheritance cycle: {} What it means
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.
Source
Thrown at ecc2/src/config/mod.rs:473
}
Ok(ResolvedOrchestrationTemplate {
template_name: name.to_string(),
description,
project,
task_group,
steps,
})
}
fn resolve_agent_profile_inner(
&self,
name: &str,
chain: &mut Vec<String>,
) -> Result<ResolvedAgentProfile> {
if chain.iter().any(|existing| existing == name) {
chain.push(name.to_string());
anyhow::bail!("agent profile inheritance cycle: {}", chain.join(" -> "));
}
let profile = self
.agent_profiles
.get(name)
.ok_or_else(|| anyhow::anyhow!("Unknown agent profile: {name}"))?;
chain.push(name.to_string());
let mut resolved = if let Some(parent) = profile.inherits.as_deref() {
self.resolve_agent_profile_inner(parent, chain)?
} else {
ResolvedAgentProfile::default()
};
chain.pop();
resolved.apply(name, profile);
Ok(resolved)
}View on GitHub (pinned to 01e15490f0)
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.
Example fix
# before [agent_profiles.base] inherits = "child" [agent_profiles.child] inherits = "base" # after [agent_profiles.base] [agent_profiles.child] inherits = "base"
Defensive patterns
Strategy: validation
Validate before calling
// Static check over the agent_profiles inherits graph before runtime.
fn inherits_graph_is_acyclic(cfg: &Config) -> Result<()> {
let mut color: HashMap<&str, u8> = HashMap::new(); // 0=white,1=gray,2=black
fn visit<'a>(cfg: &'a Config, n: &'a str, color: &mut HashMap<&'a str, u8>) -> Result<()> {
match color.get(n).copied() {
Some(2) => return Ok(()),
Some(1) => anyhow::bail!("cycle detected at {n}"),
_ => {}
}
color.insert(n, 1);
if let Some(p) = cfg.agent_profile(n).and_then(|p| p.inherits.as_deref()) {
visit(cfg, p, color)?;
}
color.insert(n, 2);
Ok(())
}
for name in cfg.agent_profile_names() { visit(cfg, name, &mut color)?; }
Ok(())
} Type guard
fn profile_inherits_is_acyclic(cfg: &Config, start: &str) -> bool {
let mut seen = HashSet::new();
let mut cur = Some(start);
while let Some(n) = cur {
if !seen.insert(n.to_string()) {
return false;
}
cur = cfg.agent_profile(n).and_then(|p| p.inherits.clone()).as_deref();
}
true
} Try / catch
let profile = cfg.resolve_agent_profile(name).map_err(|e| {
if e.to_string().contains("inheritance cycle") {
anyhow::anyhow!("{e}; remove the back-edge in the inherits chain")
} else {
e
}
})?; Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unknown agent profile: {name}
- Unknown orchestration template: {name}
- orchestration template {name} has no steps
- missing orchestration template variable(s): {}
- worktree_branch_prefix cannot be empty
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3890510ffdb12957.
Report an issue: GitHub.