Hmbown/CodeWhale · error · anyhow::Error

dispatch task was lost: {err}

Error message

dispatch task was lost: {err}

What it means

The dispatch pipeline runs its owned async phase via tokio::spawn (spawned_dispatch_inner) and awaits the JoinHandle. A JoinError means the task never produced a result: it panicked, or the runtime shut down and cancelled it. The error wraps the JoinError text (e.g. 'task 42 panicked with …' or 'task 42 was cancelled'), so the real fault is upstream of this wrapper.

Source

Thrown at crates/tui/src/tui/ui/event_loop.rs:5509

pub(crate) async fn run_prepared_dispatch(
    app: &mut App,
    config: &Config,
    engine_handle: &EngineHandle,
    prepare: UserDispatchPrepare,
    recovery: DispatchRecovery,
) -> Result<()> {
    // Unit tests that intentionally omit the production completion mailbox
    // apply the result inline. Run the owned async phase as a task just like
    // production does so its large future is polled from a clean executor
    // stack instead of nesting under the test helper's call chain.
    let apply = tokio::spawn(spawned_dispatch_inner(
        prepare,
        recovery,
        engine_handle.clone(),
    ))
    .await
    .map_err(|err| anyhow::anyhow!("dispatch task was lost: {err}"))?;
    apply(app, engine_handle, config)
}

pub(crate) async fn run_xai_device_login_from_tui(
    terminal: &mut AppTerminal,
    app: &mut App,
    engine_handle: &mut EngineHandle,
    config: &mut Config,
) -> Result<bool> {
    pause_terminal(
        terminal,
        app.use_alt_screen,
        app.use_mouse_capture,
        app.use_bracketed_paste,
    )?;
    let login_result = crate::xai_oauth::device_code_login().await;
    resume_terminal(
        terminal,

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Check logs/stderr for the panic message and backtrace - the root cause is inside the dispatched action, not this wrapper
  2. Update to the latest build and search the issue tracker for the action you ran
  3. Reproduce with RUST_BACKTRACE=1 and report the backtrace
  4. Avoid the triggering action until a fix lands
Defensive patterns

Strategy: try-catch

Try / catch

let handle = tokio::spawn(spawned_dispatch_inner(prepare, recovery, engine_handle.clone()));
match handle.await {
    Ok(apply) => apply(app, engine_handle, config),
    Err(join) if join.is_panic() => {
        let panic = join.into_panic();
        tracing::error!("dispatch panicked: {:?}", panic);
        recover_gracefully() // keep TUI alive; report the action that panicked
    }
    Err(join) => handle_shutdown_cancellation(join),
}

Prevention

When it happens

Trigger: A panic (unwrap/expect/index out of bounds) inside dispatch preparation or an action handler running in spawned_dispatch_inner; tokio runtime shutdown aborting the task mid-flight; JoinError::is_cancelled during teardown.

Common situations: A bug in a specific action handler triggered by particular app state; tests dropping the runtime early; graceful-shutdown races cancelling in-flight dispatch.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/96ff02b813c0c0f6. Report an issue: GitHub.