tinyhumansai/openhuman · error
agent `{parent}` ({ptier}) lists `{child}` ({ctier}) in suba
Error message
agent `{parent}` ({ptier}) lists `{child}` ({ctier}) in subagents — {reason} What it means
Same boot-time validator (loader.rs:433), wrapping a validate_tier_transition failure: the parent's tier may not delegate to the child's tier. Forbidden pairs are Chat→Chat (would defeat the whole point of the fast tier) and Reasoning→Reasoning (depth-blowing recursion of slow models). The pair-rule is the single source of truth shared with the runtime spawn gate in run_subagent, so the definition is rejected at boot with the offending ids and tiers spelled out.
Source
Thrown at src/openhuman/agent/registry/agents/loader.rs:433
);
}
let Some(child_tier) = tier_by_id.get(child_id).copied() else {
// Unknown id — that's a separate `subagents` integrity
// concern (covered by existing tests / runtime spawn
// resolution); don't mask it as a tier error.
continue;
};
// Same-tier delegation is forbidden for chat and reasoning.
// (Chat→Chat would defeat the whole point of the fast tier;
// Reasoning→Reasoning produces a depth-blowing recursion of
// slow models.) The pair-rule lives in `validate_tier_transition`
// (the single source of truth shared with the runtime spawn gate
// in `run_subagent`); here we wrap its reason with the offending
// agent ids + tiers for a boot-time-friendly diagnostic.
if let Err(reason) = validate_tier_transition(def.agent_tier, child_tier) {
anyhow::bail!(
"agent `{parent}` ({ptier}) lists `{child}` ({ctier}) in subagents — {reason}",
parent = def.id,
ptier = def.agent_tier.as_str(),
child = child_id,
ctier = child_tier.as_str(),
);
}
}
}
Ok(())
}
/// Parse a single [`BuiltinAgent`] triple into a finished [`AgentDefinition`].
fn parse_builtin(b: &BuiltinAgent) -> Result<AgentDefinition> {
// The TOML ships without `system_prompt` — serde falls back to
// `defaults::empty_inline_prompt` — and the loader injects the
// rendered sibling `prompt.md` immediately below.View on GitHub (pinned to a221052e0d)
Solutions
- Change the child's agent_tier (e.g. make the inner executor a worker) so the transition is allowed
- Remove the subagents entry if the delegation is not needed
- Move the delegation up a level: let an orchestrator/reasoning parent own both agents instead of chaining same-tier peers
- Re-run registry load to confirm a clean boot
Example fix
# before — both tiers are "reasoning" [agent "reviewer"] subagents = ["second_reviewer"] # after — inner agent becomes a worker leaf [agent "reviewer"] subagents = [] # or set second_reviewer: agent_tier = "worker"
Defensive patterns
Strategy: validation
Validate before calling
// Same validator catches both worker-leaf and tier-transition violations pre-boot: openhuman::agent::registry::agents::validate_tier_hierarchy(&defs)?;
Type guard
// Allowed delegation pairs, mirroring validate_tier_transition
fn transition_ok(parent: AgentTier, child: AgentTier) -> bool {
!matches!((parent, child),
(AgentTier::Chat, AgentTier::Chat) |
(AgentTier::Reasoning, AgentTier::Reasoning))
} Try / catch
// On boot failure, parse out parent/child ids from the message to point at the TOML
if let Err(e) = registry.load() {
let msg = e.to_string();
if msg.contains("in subagents") {
eprintln!("tier-hierarchy violation: {msg}\nChange the child's tier or remove the entry.");
}
return Err(e);
} Prevention
- Design teams top-down: orchestrator/reasoning parents over worker leaves
- Never chain two same-tier (chat-chat, reasoning-reasoning) agents
- Re-run validate_tier_hierarchy whenever tiers change in any agent TOML
When it happens
Trigger: A chat-tier agent listing another chat-tier agent in subagents; a reasoning-tier agent listing another reasoning-tier agent; adding a new agent to a team and wiring it under a same-tier peer.
Common situations: Building multi-agent teams in TOML with every agent defaulted to the same tier; refactoring agent tiers without re-checking the subagents graph.
Related errors
- agent `{parent}` is a `worker` tier and must not list `{chil
- API base URL must be an absolute http(s) URL with host
- learning_save_profile: {e}
- learning_enrich_profile: {e}
- Core returned an empty backend URL
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/7216bffc4324da7e.
Report an issue: GitHub.