Hmbown/CodeWhale · error

Sub-agent token budget exhausted; continuation cannot reset…

Error message

Sub-agent token budget exhausted; continuation cannot reset its inherited allowance

What it means

This error is thrown in `spawn_background_with_assignment_options` (crates/tui/src/tools/subagent/mod.rs:6938) when a sub-agent is spawned or continued and its inherited token allowance is exactly zero. Continuations and forks inherit the remaining token budget of their source/parent agent (`resume_from_agent_id` or `runtime.parent_agent_id`); the library refuses the spawn because a new child could never run any model turns under an empty allowance, and starting it would silently reset the accounting. It is an explicit anti-loophole guard: a continuation must live inside the parent's remaining budget, not mint a fresh one.

Solutions

  1. Finish the parent agent's task or accept it is done; do not continue a fully spent agent.
  2. Spawn a fresh sub-agent with an explicit, larger `token_budget` option instead of continuing the exhausted one.
  3. Raise the token budget on the parent/source worker profile so `remaining_worker_tokens` is positive before continuing.
  4. Increase `default_token_budget` in the sub-agent manager config so newly spawned workers get a larger allowance.

Example fix

// before: continuing an exhausted agent
spawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools,
    SubAgentSpawnOptions { resume_from_agent_id: Some(spent_agent_id), .. })
// after: fresh agent with a new budget
spawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools,
    SubAgentSpawnOptions { token_budget: Some(64_000), .. })
Defensive patterns

Strategy: validation

Validate before calling

fn can_continue(manager: &SubAgentManager, options: &SubAgentSpawnOptions, runtime: &SubAgentRuntime) -> bool {
    let parent = options.resume_from_agent_id.as_deref()
        .or(runtime.parent_agent_id.as_deref());
    match parent.map(|id| manager.remaining_worker_tokens(id)) {
        Some(Some(0)) => false,
        _ => true,
    }
}

Type guard

fn has_inherited_budget(remaining: Option<u64>) -> bool {
    remaining.map_or(true, |r| r > 0)
}

Try / catch

match manager.spawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools, options) {
    Ok(result) => /* ... */,
    Err(e) if e.to_string().contains("token budget exhausted") => {
        // fall back to spawning a fresh agent with a new token_budget
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the sub-agent spawn tool with `resume_from_agent_id` (or having a parent agent id set) when `remaining_worker_tokens(parent_id)` returns `Some(0)` — i.e. the parent/source worker already consumed its entire `token_budget`. Typical call: spawning a continuation/fork of an agent whose token allowance is fully spent.

Common situations: (1) A long-running sub-agent burned through its token budget and the orchestrator tries to continue it with a follow-up/fork. (2) Chained continuations where each generation narrows the inherited budget until it hits zero. (3) A misconfigured `token_budget` (or a very small per-call `token_budget` option) that is exhausted almost immediately, so any continuation attempt fails. (4) Resuming after a session reload where the manifest's preserved token budget was already fully consumed.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/91dde0a596302227. Report an issue: GitHub.

Appendix: source

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

                narrow_optional_limit(runtime.worker_profile.token_budget, preserved.token_budget);
            runtime.worker_profile.max_steps =
                narrow_model_steps(runtime.worker_profile.max_steps, preserved.max_steps);
            runtime.worker_profile.wall_time_secs = narrow_optional_limit(
                runtime.worker_profile.wall_time_secs,
                preserved.wall_time_secs,
            );
            runtime.worker_profile.wall_deadline_ms = narrow_optional_limit(
                runtime.worker_profile.wall_deadline_ms,
                preserved.wall_deadline_ms,
            );
        }
        let budget_parent = options
            .resume_from_agent_id
            .as_deref()
            .or(runtime.parent_agent_id.as_deref());
        let inherited_remaining = budget_parent.and_then(|id| self.remaining_worker_tokens(id));
        if inherited_remaining == Some(0) {
            return Err(anyhow!(
                "Sub-agent token budget exhausted; continuation cannot reset its inherited allowance"
            ));
        }
        let effective_token_budget = narrow_optional_limit(
            narrow_optional_limit(runtime.worker_profile.token_budget, inherited_remaining),
            narrow_optional_limit(
                self.default_token_budget,
                positive_token_budget(options.token_budget),
            ),
        );
        let mut max_steps = narrow_model_steps(
            runtime.worker_profile.max_steps,
            resolve_max_steps(agent_type.clone(), options.max_steps, self.max_steps),
        );
        if let Some(source) = options
            .resume_from_agent_id
            .as_deref()
            .and_then(|id| self.worker_records.get(id))

View on GitHub (pinned to 433685b202)