Hmbown/CodeWhale · error · anyhow::Error

child wall-time budget exhausted

Error message

child wall-time budget exhausted (limit: {}s); partial work is preserved; narrow the task or have the operator raise the inherited limit

What it means

When launching a sub-agent, the launch wait has a deadline; if launching itself times out (launch_wait_timed_out), the child's cancel token is fired and this error is returned immediately via child_wall_time_exhausted_reason. A 30-second backstop beyond the deadline is kept so a graceful inner receipt can still win, but the hard anti-hang guarantee stands: the child gets no more than its inherited wall-time budget plus grace.

Solutions

  1. Narrow the sub-agent task so it fits within the inherited wall-time budget
  2. Have the operator raise the child's time limit in the runtime envelope/config
  3. Check for a hanging tool call or provider request keeping the child from finishing startup
  4. Inspect the child's partial work (it is preserved) to see where the time went

Example fix

// before: broad task on a tight inherited budget
subagent.run("refactor the entire module", limit = 60s);
// after: narrowed task, or raised operator limit
subagent.run("rename Foo to Bar in module X", limit = 300s);
Defensive patterns

Strategy: try-catch

Validate before calling

let budget = child.time_limit();
if estimated_task_duration > budget {
    return Err("task too broad for inherited limit; narrow it".into());
}

Try / catch

match run_subagent_task(task).await {
    Err(e) if e.to_string().contains("wall-time budget exhausted") => {
        // partial work is preserved; inspect and resume with a narrower task
        resume_from_partial(&task.agent_id)?
    }
    other => other,
}

Prevention

When it happens

Trigger: A sub-agent task whose startup/launch phase does not complete within its inherited wall-time deadline — the launch wait times out, cancellation is triggered, and this error is surfaced with the effective limit in seconds.

Common situations: A task prompt that is far too broad for its budget, an operator-configured deadline that is too small for the task, or a child hanging during startup (blocked tool, dead provider) so it never finishes launching in time.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

    }

    let turn_end_parking = task
        ._foreground_child_registration
        .as_ref()
        .map(ForegroundChildRegistration::parking_signal);
    // Every inner stage bounds itself by `deadline` (step requests by the
    // work deadline, and the reserved hand-back turn by the hard deadline),
    // so the inner run can always produce its own receipt: the specific stop
    // cause, the hand-back outcome, and preserved usage. This outer backstop
    // exists only for an inner stage that overruns anyway; racing it at the
    // same instant as the inner deadline replaced real receipts with the
    // generic error below (#6277). The grace keeps the anti-hang guarantee
    // while letting the inner receipt win.
    let backstop = deadline + Duration::from_secs(30);
    let effective_limit = deadline.saturating_duration_since(task.started_at);
    let result = if launch_wait_timed_out {
        task.runtime.cancel_token.cancel();
        Err(anyhow!(child_wall_time_exhausted_reason(effective_limit)))
    } else {
        tokio::time::timeout_at(
            backstop.into(),
            run_subagent(
                &task.runtime,
                task.agent_id.clone(),
                task.agent_type,
                task.prompt,
                task.assignment,
                task.allowed_tools,
                task.fork_context,
                task.started_at,
                task.max_steps,
                turn_end_parking,
                task.input_rx,
            ),
        )
        .await

View on GitHub (pinned to 73e0f67d83)