tinyhumansai/openhuman · error
agent `{parent}` is a `worker` tier and must not list `{chil
Error message
agent `{parent}` is a `worker` tier and must not list `{child}` in its subagents — workers are leaf executors. What it means
Boot-time agent-registry validation (validate_tier_hierarchy, loader.rs:410): an agent declared agent_tier = "worker" lists an AgentId entry in subagents. Workers are leaf executors with no open-ended spawn surface, so the whole registry load fails. Only SubagentEntry::Skills wildcards are exempt (they collapse to one delegation tool on integrations_agent, itself a Worker). The check runs for bundled archetypes and again after workspace-local TOML overrides merge, so violating custom agents fail boot rather than crash at spawn time.
Source
Thrown at src/openhuman/agent/registry/agents/loader.rs:410
/// agents that violate the contract fail the boot rather than crashing
/// at spawn time.
pub fn validate_tier_hierarchy(defs: &[AgentDefinition]) -> Result<()> {
let tier_by_id: HashMap<&str, AgentTier> =
defs.iter().map(|d| (d.id.as_str(), d.agent_tier)).collect();
for def in defs {
for entry in &def.subagents {
let child_id = match entry {
SubagentEntry::AgentId(id) => id.as_str(),
// Workflow wildcards always route to `integrations_agent`
// (a Worker) via a single collapsed delegation tool —
// not subject to the tier-mismatch rule.
SubagentEntry::Skills(_) => continue,
};
// Worker leaves: no open-ended spawn surface.
if def.agent_tier == AgentTier::Worker {
anyhow::bail!(
"agent `{parent}` is a `worker` tier and must not list `{child}` in its \
subagents — workers are leaf executors.",
parent = def.id,
child = child_id,
);
}
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`View on GitHub (pinned to a221052e0d)
Solutions
- Remove the subagents list (or the AgentId entries) from the worker agent's TOML — workers stay leaf executors
- If delegation is intentional, raise the parent's agent_tier to chat/reasoning/orchestrator as appropriate
- If the goal was workflow/skill access, use the skills wildcard entry ({ skills = "*" }), which is exempt from this rule
- Reload the agent registry / restart the core after fixing the TOML
Example fix
# before
id = "indexer"
agent_tier = "worker"
subagents = ["search_agent"]
# after — leaf executor, or use the exempt wildcard
id = "indexer"
agent_tier = "worker"
subagents = [{ skills = "*" }] Defensive patterns
Strategy: validation
Validate before calling
// Lint definitions with the same rule the loader enforces, before boot:
openhuman::agent::registry::agents::validate_tier_hierarchy(&defs)
.context("agent TOML rejected before registry load")?; Type guard
// A worker must be a leaf: no AgentId subagent entries allowed
fn worker_is_leaf(def: &AgentDefinition) -> bool {
def.agent_tier != AgentTier::Worker
|| def.subagents.iter().all(|s| matches!(s, SubagentEntry::Skills(_)))
} Try / catch
// Around AgentDefinitionRegistry::load — surface the offending file, not a raw bail
match registry.load() {
Ok(_) => {},
Err(e) if e.to_string().contains("worker` tier") => {
eprintln!("agent config error: {e:#}\nRemove subagents from the worker agent or raise its tier.");
std::process::exit(2);
}
Err(e) => return Err(e),
} Prevention
- Treat worker agents as leaf executors by design — never add subagents to them
- Use the { skills = "*" } wildcard when a worker needs workflow access
- Run validate_tier_hierarchy in a config-lint step for custom workspace agents
When it happens
Trigger: A workspace agent TOML with agent_tier = "worker" plus subagents = ["some_agent"]; copying a chat/orchestrator agent file and changing only the tier field to worker; editing ~/.openhuman agent overrides by hand.
Common situations: Users customizing workspace agent TOMLs; attempting to give a worker access to another agent by listing it as a subagent instead of using the skills wildcard.
Related errors
- agent `{parent}` ({ptier}) lists `{child}` ({ctier}) in suba
- 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/7a6c5b81b33e277e.
Report an issue: GitHub.