Hmbown/CodeWhale · error

Failed to promote staged task

Error message

Failed to promote staged task {task.id}: {promote_err}

What it means

Promoting a staged (queued) task from its staging file into the active queue failed. Task_manager stages a task to disk first, then atomically promotes it; if promotion errors, it attempts a queue rollback and staged-file cleanup, and folds every secondary failure into one message so no failure is silently dropped. The task remains staged (or partially rolled back) — it was not activated.

Solutions

  1. Read the chained promote_err (plus rollback/cleanup notes) to identify the failing step.
  2. Check whether the staged task file still exists at the staged_task_path shown/derived from the queue directory.
  3. Fix the underlying cause (disk space, permissions, concurrent writer) and re-run promotion.
  4. If the staged file is orphaned and the queue is intact, remove the stale staged file manually and re-enqueue the task.
  5. Verify the queue schema version matches after a Codewhale upgrade.
Defensive patterns

Strategy: try-catch

Validate before calling

// before promoting, confirm the staged file exists and the queue is writable
if !tokio::fs::try_exists(&staged_task_path).await.unwrap_or(false) {
    // staged file missing: re-stage or abort promotion
}
let md = tokio::fs::metadata(&queue_path).await?;
if md.permissions().readonly() {
    // promotion would fail
}

Try / catch

// Rust
match task_manager.promote(task_id).await {
    Err(e) if e.to_string().contains("Failed to promote staged task") => {
        // check rollback/cleanup notes in message; clear stale staged file; re-enqueue
    }
    other => other?,
}

Prevention

When it happens

Trigger: `promote` of a staged task at task_manager.rs fails (queue write error, IO error on the queue file); the subsequent `tokio::fs::remove_file(&staged_task_path)` or queue rollback may also fail, each appending to the message.

Common situations: The queue store is locked by a concurrent writer; the staged file was deleted or renamed externally between staging and promotion; permission or disk-full errors; the staged task JSON no longer matches the queue's expected schema after an upgrade.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

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

                {
                    tracing::warn!(
                        task_id = %task.id,
                        error = %cleanup_err,
                        "failed to remove ignored staged task after queue write failure"
                    );
                }
                return Err(err);
            }
            if let Err(promote_err) = tokio::fs::rename(&staged_task_path, &task_path).await {
                let rollback_error = self.persist_queue_locked(&state.queue).err();
                let cleanup_error = if recover_stage {
                    None
                } else {
                    tokio::fs::remove_file(&staged_task_path).await.err()
                };
                let mut message =
                    format!("Failed to promote staged task {}: {promote_err}", task.id);
                if let Some(rollback_error) = rollback_error {
                    message.push_str(&format!("; queue rollback also failed: {rollback_error:#}"));
                }
                if let Some(cleanup_error) = cleanup_error {
                    message.push_str(&format!(
                        "; ignored staged-file cleanup also failed: {cleanup_error}"
                    ));
                }
                bail!(message);
            }
            state.queue = next_queue;
            state.tasks.insert(task.id.clone(), task.clone());
        }
        self.notify.notify_one();
        Ok(task)
    }

    /// List tasks, newest first.
    pub async fn list_tasks(&self, limit: Option<usize>) -> Result<Vec<TaskSummary>> {

View on GitHub (pinned to 73e0f67d83)