Hmbown/CodeWhale · error

Task execution scope is unverified or belongs to another…

Error message

Task execution scope is unverified or belongs to another Runtime; refusing adoption

What it means

During admission, a task record's execution_scope must exactly match the current Runtime's execution_scope(). A record whose scope is missing (unverified) or belongs to another Runtime is refused for adoption, preventing a worker from executing tasks created under a different execution identity (different lease namespace/generation).

Solutions

  1. Only adopt task records produced by the same Runtime/scope; verify task.execution_scope equals the current execution_scope() before admission
  2. Delete or archive durable task files from foreign scopes so recovery does not attempt to adopt them
  3. If scopes legitimately changed across an upgrade, run the migration that re-stamps records with the new scope
  4. Set execution_scope explicitly when constructing TaskRecord; never admit records with a None scope

Example fix

// before
mgr.adopt_task(record).await?; // record.execution_scope = Some("old-scope")
// after
if record.execution_scope.as_deref() == Some(mgr.execution_scope()) {
    mgr.adopt_task(record).await?;
} else {
    archive_foreign_task(&record)?;
}
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(task.execution_scope.as_deref() == Some(mgr.execution_scope()), "task belongs to another runtime scope");

Try / catch

match adopt_result { Err(e) if e.to_string().contains("execution scope") => archive_foreign_record(&task), r => r?, }

Prevention

When it happens

Trigger: Calling admit_task_record (via recovery, adoption, or add paths) with a TaskRecord whose execution_scope is None or whose stored scope string differs from self.execution_scope() — e.g. a task file copied from another profile/machine or created before a scope regeneration.

Common situations: Copying a tasks directory between machines or profiles; runtime scope regenerating after an id-format change (related to validate_execution_id); loading old durable records from a previous version that stored no scope.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

                kind: "queued".to_string(),
                summary: "Task queued".to_string(),
                detail_path: None,
            }],
        };

        self.admit_task_record(task, false).await
    }

    async fn admit_task_record(&self, task: TaskRecord, recover_stage: bool) -> Result<TaskRecord> {
        {
            let mut state = self.state.lock().await;
            let _transaction = self.lock_store().await?;
            self.refresh_locked(&mut state)?;
            if self.cancel_token.is_cancelled() {
                bail!("Task manager is shutting down; admission is closed");
            }
            if task.execution_scope.as_deref() != Some(self.execution_scope()) {
                bail!(
                    "Task execution scope is unverified or belongs to another Runtime; refusing adoption"
                );
            }
            let task_path = self.tasks_dir.join(format!("{}.json", task.id));
            // The staged extension is intentionally not `.json`, so startup
            // replay ignores an interrupted create until the queue write has
            // succeeded and this file is atomically promoted.
            let staged_task_path = self.tasks_dir.join(format!(".{}.json.pending", task.id));
            if recover_stage {
                if let Some(accepted) = self.read_bound_task(&task.id)? {
                    validate_bound_task_request(&accepted, &NewTaskRequest::from_task(&task))?;
                    return Ok(accepted);
                }
                let current = read_bound_task_file(&staged_task_path, &task.id)?
                    .context("Unaccepted task stage disappeared during recovery")?;
                if serde_json::to_value(&current)? != serde_json::to_value(&task)? {
                    bail!("Unaccepted task stage changed during recovery");
                }

View on GitHub (pinned to 73e0f67d83)