Hmbown/CodeWhale · error

Task not found

Error message

Task not found: {task_id}

What it means

TaskManager::get_task_for_active_runtime throws this when a trusted runtime thread looks up a task by its full durable id and the record is either missing or fails the visibility filter: a scoped task whose execution_scope differs from the current scope, or an ownerless legacy task with no owner_session_id. Ownerless tasks without that provenance fail closed deliberately.

Solutions

  1. Confirm the task_id is the full durable id stamped on the runtime thread, not a prefix or model-supplied value.
  2. Re-create or re-scope the task so its execution_scope matches the current manager scope after a restart.
  3. Stamp owner_session_id provenance onto legacy ownerless records so they no longer fail closed.
  4. Re-check the task list immediately before lookup; retry with a fresh id if the task ended and was pruned.

Example fix

// before
let task = manager.get_task_for_active_runtime(&stale_id).await?;
// after
let task = match manager.get_task_for_active_runtime(&durable_id).await {
    Ok(t) => t,
    Err(e) => {
        tracing::warn!(id = %durable_id, "runtime task invisible or pruned");
        return Err(e);
    }
};
Defensive patterns

Strategy: validation

Validate before calling

// Only pass full durable ids stamped onto the runtime thread, never prefixes.
if !task_id.is_empty() && task_id.len() < FULL_ID_LEN { return Err(anyhow!("runtime requires full durable id")); }

Type guard

fn is_full_durable_id(s: &str) -> bool { s.len() >= FULL_ID_LEN && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') }

Try / catch

match manager.get_task_for_active_runtime(&task_id).await {
    Ok(task) => proceed(task),
    Err(e) => {
        tracing::warn!(%task_id, "task invisible to this runtime scope; re-scoping");
        re_bind_task_to_scope(task_id)
    }
}

Prevention

When it happens

Trigger: Calling get_task_for_active_runtime(task_id) from a runtime thread when: the task id does not exist in state.tasks; the task's execution_scope string differs from self.execution_scope() (e.g. manager restarted, scope re-derived); or the task has execution_scope == None and owner_session_id == None (legacy unowned record).

Common situations: A resumed session or process restart changed the execution scope so previously valid task ids are now invisible; the runtime thread passes a stale id after the task was completed and pruned; a migrated pre-scoping task record has no owner/scope provenance and is hidden by design.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/task_manager.rs:1968

    /// Retrieve the exact owned task stamped onto a trusted runtime thread.
    ///
    /// The runtime thread supplies a full durable id rather than model input.
    /// An ownerless task needs the current trusted execution scope. Legacy
    /// ownerless tasks without that provenance still fail closed.
    pub(crate) async fn get_task_for_active_runtime(&self, task_id: &str) -> Result<TaskRecord> {
        let mut state = self.state.lock().await;
        let _transaction = self.lock_store().await?;
        self.refresh_locked(&mut state)?;
        state
            .tasks
            .get(task_id)
            .filter(|task| match task.execution_scope.as_deref() {
                Some(scope) => scope == self.execution_scope(),
                None => task.owner_session_id.is_some(),
            })
            .cloned()
            .ok_or_else(|| anyhow!("Task not found: {task_id}"))
    }

    async fn get_task_visible_to(
        &self,
        id_or_prefix: &str,
        owner_session_id: Option<&str>,
    ) -> Result<TaskRecord> {
        let mut state = self.state.lock().await;
        let _transaction = self.lock_store().await?;
        self.refresh_locked(&mut state)?;
        let id = resolve_task_id_visible_to(&state.tasks, id_or_prefix, owner_session_id)?;
        state
            .tasks
            .get(&id)
            .cloned()
            .ok_or_else(|| anyhow!("Task not found: {id_or_prefix}"))
    }

View on GitHub (pinned to 73e0f67d83)