tinyhumansai/openhuman · error · SubagentRunError::SpawnDepthExceeded

sub-agent spawn depth exceeded: attempted depth {attempted_d

Error message

sub-agent spawn depth exceeded: attempted depth {attempted_depth}, max {max_depth}

What it means

A sub-agent attempted to spawn at a nesting depth beyond the configured maximum (attempted_depth vs max_depth). This is the recursion guard that prevents unbounded agent-spawns-agent chains exhausting stack (the default 2 MiB tokio worker stack overflows on deep delegation) and cost. tinyagents reports it as LimitExceeded; the dispatcher orders cap/depth mappings ahead of the error slot so it surfaces as the depth error rather than a stale provider error, keeping classification and Sentry suppression correct.

Source

Thrown at src/openhuman/agent/tinyagents/mod.rs:961

            // path) maps to the typed `AgentError::MaxIterationsExceeded` so
            // callers downcast it (Sentry skip) and render the canonical
            // "Agent exceeded maximum tool iterations" message, matching the
            // legacy `ErrorCheckpoint`.
            if let tinyagents::TinyAgentsError::LimitExceeded(msg) = &e {
                if msg.contains("model call") {
                    tracing::debug!(
                        model,
                        "[tinyagents] run hit the model-call cap; mapping to MaxIterationsExceeded (not consulting error_slot) — #4457 defect B"
                    );
                    return Err(anyhow::Error::new(
                        crate::openhuman::agent::error::AgentError::MaxIterationsExceeded {
                            max: max_iterations,
                        },
                    ));
                }
            }
            if let Some(depth_err) = tinyagents_depth_error(&e) {
                return Err(anyhow::Error::new(depth_err));
            }
            // Otherwise prefer the original typed provider error (preserves
            // `AgentError` downcasts the caller relies on) over the harness's
            // string wrap — this is where a genuine model/provider failure that
            // halted the run is re-surfaced with its real classification.
            // #4469 item 3: `into_inner` recovers a poisoned slot so a panic in
            // one run can't cascade into a second panic here that would mask the
            // original typed provider error.
            if let Some(original) = error_slot
                .lock()
                .unwrap_or_else(std::sync::PoisonError::into_inner)
                .take()
            {
                tracing::debug!(
                    model,
                    "[tinyagents] re-surfacing typed provider error from error_slot as the run failure — #4457 defect B"
                );
                return Err(original);

View on GitHub (pinned to 7491200858)

Solutions

  1. Flatten the delegation: have the parent agent do the work directly instead of spawning another nested sub-agent
  2. Restructure the orchestration so sub-agents are siblings spawned by the orchestrator, not children of other workers
  3. Raise max spawn depth in harness configuration only if the topology genuinely requires deeper nesting
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/openhuman/agent/tinyagents/mod.rs:961 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/fb9c00a33514f6c1. Report an issue: GitHub.