{"record":{"id":"91dde0a596302227","repo":"Hmbown/CodeWhale","slug":"sub-agent-token-budget-exhausted-continuation-cannot-reset","errorCode":null,"errorMessage":"Sub-agent token budget exhausted; continuation cannot reset its inherited allowance","messagePattern":"Sub-agent token budget exhausted; continuation cannot reset its inherited allowance","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6938,"sourceCode":"                narrow_optional_limit(runtime.worker_profile.token_budget, preserved.token_budget);\n            runtime.worker_profile.max_steps =\n                narrow_model_steps(runtime.worker_profile.max_steps, preserved.max_steps);\n            runtime.worker_profile.wall_time_secs = narrow_optional_limit(\n                runtime.worker_profile.wall_time_secs,\n                preserved.wall_time_secs,\n            );\n            runtime.worker_profile.wall_deadline_ms = narrow_optional_limit(\n                runtime.worker_profile.wall_deadline_ms,\n                preserved.wall_deadline_ms,\n            );\n        }\n        let budget_parent = options\n            .resume_from_agent_id\n            .as_deref()\n            .or(runtime.parent_agent_id.as_deref());\n        let inherited_remaining = budget_parent.and_then(|id| self.remaining_worker_tokens(id));\n        if inherited_remaining == Some(0) {\n            return Err(anyhow!(\n                \"Sub-agent token budget exhausted; continuation cannot reset its inherited allowance\"\n            ));\n        }\n        let effective_token_budget = narrow_optional_limit(\n            narrow_optional_limit(runtime.worker_profile.token_budget, inherited_remaining),\n            narrow_optional_limit(\n                self.default_token_budget,\n                positive_token_budget(options.token_budget),\n            ),\n        );\n        let mut max_steps = narrow_model_steps(\n            runtime.worker_profile.max_steps,\n            resolve_max_steps(agent_type.clone(), options.max_steps, self.max_steps),\n        );\n        if let Some(source) = options\n            .resume_from_agent_id\n            .as_deref()\n            .and_then(|id| self.worker_records.get(id))","sourceCodeStart":6920,"sourceCodeEnd":6956,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tools/subagent/mod.rs#L6920-L6956","documentation":"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.","triggerScenarios":"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.","commonSituations":"(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.","solutions":["Finish the parent agent's task or accept it is done; do not continue a fully spent agent.","Spawn a fresh sub-agent with an explicit, larger `token_budget` option instead of continuing the exhausted one.","Raise the token budget on the parent/source worker profile so `remaining_worker_tokens` is positive before continuing.","Increase `default_token_budget` in the sub-agent manager config so newly spawned workers get a larger allowance."],"exampleFix":"// before: continuing an exhausted agent\nspawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools,\n    SubAgentSpawnOptions { resume_from_agent_id: Some(spent_agent_id), .. })\n// after: fresh agent with a new budget\nspawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools,\n    SubAgentSpawnOptions { token_budget: Some(64_000), .. })","handlingStrategy":"validation","validationCode":"fn can_continue(manager: &SubAgentManager, options: &SubAgentSpawnOptions, runtime: &SubAgentRuntime) -> bool {\n    let parent = options.resume_from_agent_id.as_deref()\n        .or(runtime.parent_agent_id.as_deref());\n    match parent.map(|id| manager.remaining_worker_tokens(id)) {\n        Some(Some(0)) => false,\n        _ => true,\n    }\n}","typeGuard":"fn has_inherited_budget(remaining: Option<u64>) -> bool {\n    remaining.map_or(true, |r| r > 0)\n}","tryCatchPattern":"match manager.spawn_background_with_assignment_options(handle, runtime, role, prompt, assignment, tools, options) {\n    Ok(result) => /* ... */,\n    Err(e) if e.to_string().contains(\"token budget exhausted\") => {\n        // fall back to spawning a fresh agent with a new token_budget\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Check remaining_worker_tokens(source_id) before issuing any continuation.","Track cumulative token spend per agent and stop issuing followups as the budget nears zero.","Prefer spawning fresh agents with explicit token_budget over long continuation chains.","Set realistic default_token_budget values so agents are not starved mid-task."],"tags":["subagent","token-budget","budget-exhausted","continuation"],"backgroundTag":"value-out-of-range","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}