Kuberwastaken/claurst · error

failed to create a unique upgrade staging file next to

Error message

failed to create a unique upgrade staging file next to {} after {} attempts

What it means

The upgrade staging routine tried to create a uniquely-named temporary file (`.upgrade-<pid>-<n>`) next to the current binary, but every attempt collided with an already-existing file until the attempt budget ran out. The formatted values are the parent directory and attempt count. Usually means many stale staging files litter the binary's directory.

Solutions

  1. Delete stale `.upgrade-*` files from the binary's directory and retry
  2. Check the directory is writable and not full
  3. Retry the upgrade — the names include the PID so a fresh run usually picks a free slot
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at src-rust/crates/cli/src/upgrade.rs:343 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/159f0b69180909b3. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/cli/src/upgrade.rs:343

            staged_name.push(file_name);
            staged_name.push(format!(".upgrade-{}-{}", std::process::id(), id));
            let path = parent.join(staged_name);

            match OpenOptions::new().write(true).create_new(true).open(&path) {
                Ok(file) => return Ok((Self { path }, file)),
                Err(error) if error.kind() == ErrorKind::AlreadyExists => continue,
                Err(error) => {
                    return Err(error).with_context(|| {
                        format!(
                            "failed to create upgrade staging file next to {}",
                            current.display()
                        )
                    });
                }
            }
        }

        bail!(
            "failed to create a unique upgrade staging file next to {} after {} attempts",
            current.display(),
            MAX_ATTEMPTS
        )
    }
}

#[cfg(unix)]
impl Drop for StagedBinary {
    fn drop(&mut self) {
        let _ = std::fs::remove_file(&self.path);
    }
}

fn swap_binary(current: &Path, new: &Path) -> Result<()> {
    #[cfg(target_os = "windows")]
    {
        // Windows holds an exclusive lock on the running .exe — we can rename

View on GitHub (pinned to b0637c97ec)