Hmbown/CodeWhale · error · anyhow::Error

Task {task_id} not found

Error message

Task {task_id} not found

What it means

ShellManager::require_session_owner gates shell-task operations: the task id must exist in processes or stale_jobs AND its owner_session_id must equal the non-empty active session id. On failure it returns 'Task {task_id} not found' deliberately — the same message whether the id does not exist at all or belongs to another session — so callers cannot probe for other sessions' task ids.

Source

Thrown at crates/tui/src/tools/shell.rs:1720

                "foreground_background_requested",
                &self.foreground_background_requested,
            )
            .finish()
    }
}

impl ShellManager {
    fn require_session_owner(&self, task_id: &str, active_session_id: &str) -> Result<()> {
        let owned = self.processes.get(task_id).is_some_and(|shell| {
            !active_session_id.is_empty() && shell.owner_session_id == active_session_id
        }) || self.stale_jobs.get(task_id).is_some_and(|job| {
            !active_session_id.is_empty() && job.owner_session_id == active_session_id
        });
        if owned {
            Ok(())
        } else {
            // Do not disclose whether the id exists in another session.
            Err(anyhow!("Task {task_id} not found"))
        }
    }

    /// Create a new `ShellManager` with default (no sandbox) policy.
    pub fn new(workspace: PathBuf) -> Self {
        Self {
            processes: HashMap::new(),
            stale_jobs: HashMap::new(),
            default_workspace: workspace,
            sandbox_manager: SandboxManager::new(),
            sandbox_policy: ExecutionSandboxPolicy::default(),
            foreground_background_requested: false,
            output_spill_dir: None,
        }
    }

    /// Point lowercase-`bash` complete-output spill files at `dir` instead of
    /// the process temp dir. Tests use a nonexistent dir to simulate a full or

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Use only shell task ids returned by execute calls in the current session.
  2. After resume/fork/restart, re-run long-lived commands instead of addressing old task ids.
  3. Treat this message as authoritative 'not yours or not there' — do not probe variations of the id.
  4. Ensure the active session id is properly established before issuing shell operations.
Defensive patterns

Strategy: validation

Validate before calling

// Only reference shell tasks minted in this session.
let owned = shell_manager.task_ids_owned_by(active_session_id);
anyhow::ensure!(
    owned.contains(&task_id),
    "task {task_id} is not owned by this session"
);
shell_manager.poll_output(active_session_id, &task_id)?;

Try / catch

match shell_op(&task_id) {
    Ok(out) => out,
    Err(e) if e.to_string().contains("not found") => {
        // Same message for foreign-owned and missing ids; do not probe further.
        tracing::info!("shell task {task_id} not available to this session; re-running command");
        rerun_command_fresh().await?
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Any shell operation (stdin, output poll, kill, status) referencing a task id created under a different owner session, a task from a previous run before restart, or a plain typo. Also when active_session_id is empty (unset), ownership can never hold.

Common situations: After resume/fork, an agent reuses a shell task id from the pre-fork session; multiple agents share a ShellManager and one references another's background task; stale ids persisted in a transcript get replayed.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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