Hmbown/CodeWhale · error

Sub-agent admission limit reached

Error message

Sub-agent admission limit reached (max_admitted {}, admitted {}, running {}, queued {}). Wait for queued/running agents to finish, cancel unneeded agents, or raise [subagents] max_admitted for this Workflow.

What it means

The Workflow enforces a cap on how many sub-agents may exist in admitted state (running + queued). `check_admission_capacity` rejects new spawns once `admitted_count()` reaches `max_admitted_agents`, telling the caller to drain or reconfigure rather than silently queueing.

Solutions

  1. Wait for queued/running agents to finish, then retry the spawn.
  2. Cancel unneeded agents (agents/cancel or agents/remove) to free admitted slots.
  3. Raise `[subagents] max_admitted` in the Workflow config if the parallelism is intentional.
  4. Check for stuck running agents (no progress) and interrupt/clean them up.
  5. Throttle the fan-out loop to admit in batches.

Example fix

// before
[subagents]
max_admitted = 4

// after
[subagents]
max_admitted = 16  # matches expected fan-out width
Defensive patterns

Strategy: try-catch

Validate before calling

// gate fan-out before spawning
while admitted_count() >= max_admitted {
    wait_for_any_agent_to_finish().await;
}

Try / catch

match manager.check_admission_capacity() {
    Err(e) if e.to_string().contains("admission limit reached") => {
        wait_for_slot().await?;
        retry_spawn()
    }
    other => other,
}

Prevention

When it happens

Trigger: Spawning a new sub-agent (via spawn/admission path) when `admitted >= [subagents] max_admitted`; the error reports max_admitted, admitted, running, and queued counts.

Common situations: Fan-out workflows spawning more children than configured; a stuck/leaked running agent blocking admission; too-low `max_admitted` for a parallel map over many items; queued agents never draining because parents wait on them.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/570e5c90ea302b5c. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:6792

    /// Live tasks owned by this session, including queued/stalled tasks until
    /// their real terminal transition. A heartbeat projection is not proof that
    /// the task or its completion delivery has settled.
    pub(crate) fn live_count_for_session(&self, active_session_id: &str) -> usize {
        self.agents
            .values()
            .filter(|agent| {
                agent.status == SubAgentStatus::Running
                    && agent.task_handle.is_some()
                    && self.agent_is_owned_by_session(agent, active_session_id)
            })
            .count()
    }

    fn check_admission_capacity(&self) -> Result<()> {
        let admitted = self.admitted_count();
        if admitted >= self.max_admitted_agents {
            return Err(anyhow!(
                "Sub-agent admission limit reached (max_admitted {}, admitted {}, running {}, queued {}). Wait for queued/running agents to finish, cancel unneeded agents, or raise [subagents] max_admitted for this Workflow.",
                self.max_admitted_agents,
                admitted,
                self.active_count(),
                self.queued_count()
            ));
        }
        Ok(())
    }

    fn running_heartbeat_timed_out(&self, agent: &SubAgent) -> bool {
        agent.status == SubAgentStatus::Running
            && agent.task_handle.is_some()
            && agent.last_activity_at.elapsed() >= self.running_heartbeat_timeout
    }

    pub fn touch(&mut self, agent_id: &str) -> bool {
        let Some(agent) = self.agents.get_mut(agent_id) else {

View on GitHub (pinned to 73e0f67d83)