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
- Confirm the task_id is the full durable id stamped on the runtime thread, not a prefix or model-supplied value.
- Re-create or re-scope the task so its execution_scope matches the current manager scope after a restart.
- Stamp owner_session_id provenance onto legacy ownerless records so they no longer fail closed.
- 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
- After a manager restart, re-derive or re-create tasks instead of reusing pre-restart ids.
- Ensure legacy ownerless records get owner_session_id or execution_scope provenance stamped at migration time.
- Verify execution_scope matches the manager's current scope before runtime lookups.
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
- Task not found
- Cannot continue agent
- operation_key cannot exceed
- Task not found
- A pinned task provider requires an explicit model
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)