Hmbown/CodeWhale · error · anyhow::Error

Automation admission belongs to a different task store; it…

Error message

Automation admission belongs to a different task store; it cannot be replayed here

What it means

Automation replay dispatch verifies that the task data directory recorded on the AutomationDispatch matches the directory of the SharedTaskManager it is being replayed into. This error means the dispatch was created against a different task store (different data_dir), so replaying it here would write tasks into the wrong store. It is a cross-store consistency guard, not a data corruption.

Solutions

  1. Replay the dispatch against the task manager whose data_dir matches dispatch.task_data_dir.
  2. Re-generate the dispatch in the current store instead of replaying the foreign one.
  3. If the store was intentionally moved, restore it to its original canonical path, or recreate the dispatch so task_data_dir points at the current directory.

Example fix

// before
replay_dispatch(&stale_dispatch, &other_tasks).await?;
// after
if stale_dispatch.task_data_dir.canonicalize()? == other_tasks.data_dir().canonicalize()? {
    replay_dispatch(&stale_dispatch, &other_tasks).await?;
} else {
    let fresh = create_dispatch_in(&other_tasks).await?;
    replay_dispatch(&fresh, &other_tasks).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

if std::fs::canonicalize(&dispatch.task_data_dir)? != std::fs::canonicalize(tasks.data_dir())? {
    // skip replay: foreign task store
}

Try / catch

match check_dispatch_store(&dispatch, &tasks) {
    Ok(()) => replay(dispatch).await,
    Err(e) if e.to_string().contains("different task store") => recreate_dispatch(&tasks).await,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling dispatch_bound_task (or a replay/restore path that reaches check_dispatch_store) with a serialized AutomationDispatch whose task_data_dir canonicalizes to a path different from tasks.data_dir() — e.g. replaying an automation dump on a machine or profile with a different data directory.

Common situations: Copying automation state files between machines or users; running the TUI with a different CODEX_HOME / data dir than the one that produced the dispatch; restoring backups into a relocated store; pointing two profiles at each other's task stores.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/automation_manager.rs:2107

        execution_scope: automation.execution_scope.clone(),
        request: automation_task_request(automation),
        task_data_dir: task_data_dir
            .canonicalize()
            .context("resolve task store before automation admission")?,
        accepted: false,
        delivery_mode: automation.delivery_mode(),
        suppress_report: false,
        schedule: scheduled.then(|| AdmittedSchedule {
            updated_at: automation.updated_at,
            rrule: automation.rrule.clone(),
        }),
    });
    Ok(())
}

fn check_dispatch_store(dispatch: &AutomationDispatch, tasks: &SharedTaskManager) -> Result<()> {
    if tasks.data_dir().canonicalize()? != dispatch.task_data_dir.canonicalize()? {
        bail!("Automation admission belongs to a different task store; it cannot be replayed here");
    }
    Ok(())
}

async fn dispatch_bound_task(
    dispatch: &mut AutomationDispatch,
    task_id: &str,
    tasks: &SharedTaskManager,
) -> Result<crate::task_manager::TaskRecord> {
    check_dispatch_store(dispatch, tasks)?;
    if dispatch.execution_scope.as_deref() != Some(tasks.execution_scope()) {
        bail!(
            "Automation admission execution ownership is unverified or belongs to another Runtime"
        );
    }
    let task = if dispatch.accepted {
        tasks
            .read_bound_task(task_id)?

View on GitHub (pinned to 73e0f67d83)