libnyanpasu/clash-nyanpasu · error
cleanup tombstone already exists: {}
Error message
cleanup tombstone already exists: {} What it means
On Windows, destructive profile cleanup first records a tombstone file (cleanup_tombstone_path) marking the operation as in-progress so a crash can't skip the deletion. Before creating it, the code checks the tombstone doesn't already exist; if it does, the operation bails. A pre-existing tombstone means another cleanup with the same operation_id is (or was) already running, and proceeding could double-delete or race.
Source
Thrown at backend/tauri/src/service/profile_file.rs:1473
removed += 1;
}
}
}
Ok(removed)
}
fn remove_cleanup_target(
&self,
root: &Path,
operation_id: &str,
target: &Path,
) -> anyhow::Result<()> {
#[cfg(windows)]
{
let tombstone = Self::cleanup_tombstone_path(root, operation_id);
match std::fs::symlink_metadata(&tombstone) {
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
Ok(_) => bail!("cleanup tombstone already exists: {}", tombstone.display()),
Err(error) => {
return Err(error).with_context(|| {
format!("inspect cleanup tombstone {}", tombstone.display())
});
}
}
self.ensure_managed_parent(target)?;
Self::ensure_replaceable_target(target)?;
replace_atomic(target, &tombstone).with_context(|| {
format!(
"move cleanup target {} to tombstone {}",
target.display(),
tombstone.display()
)
})
}
#[cfg(not(windows))]
{View on GitHub (pinned to f7dbce2997)
Solutions
- Remove the stale tombstone at the reported path only after confirming no cleanup process is currently running, then retry.
- Prefer starting the cleanup with a fresh operation_id so the old tombstone is simply ignored by the new attempt.
- Serialize cleanup calls in your application (one at a time) to avoid two attempts sharing an id.
- If a previous cleanup is actually mid-flight, wait for it to finish instead of deleting its tombstone.
Example fix
// before: retry reuses the old id and hits the tombstone run_cleanup(root, &old_id)?; // after: new attempt, new id (old tombstone no longer conflicts) let id = generate_operation_id(); run_cleanup(root, &id)?; // or, once certain nothing is running: let _ = std::fs::remove_file(cleanup_tombstone_path(root, &old_id));
Defensive patterns
Strategy: validation
Validate before calling
fn tombstone_free(root: &Path, id: &str) -> bool {
match std::fs::symlink_metadata(cleanup_tombstone_path(root, id)) {
Err(e) => e.kind() == std::io::ErrorKind::NotFound,
Ok(_) => false,
}
} Try / catch
match run_cleanup(root, id) {
Err(e) if e.to_string().contains("cleanup tombstone already exists") => {
// confirm no cleanup is running, then remove the stale tombstone
// or restart the attempt with a fresh operation_id
}
other => other,
} Prevention
- Generate a new operation_id for each cleanup attempt instead of retrying with the old one
- Serialize cleanup invocations; never run two cleanups concurrently
- Clean up stale tombstones after confirmed-crashed runs before restarting
- Check for a live cleanup process before deleting any tombstone
When it happens
Trigger: Starting (or retrying) a profile cleanup whose Windows tombstone file for the same operation_id already exists — a previous attempt with the same id crashed before removing the tombstone, two concurrent cleanups were launched with the same id, or a leftover tombstone from a test run.
Common situations: Retrying a failed cleanup without regenerating the operation id; parallel UI actions triggering cleanup twice; interrupted runs on Windows where the tombstone was written but cleanup never completed; stale artifacts left by manual testing.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Local socket too many crashes
- proxy actor timed out; an operation may still be running, do
- enableLoopback exe not found
- managed target is an unsupported reparse point: {}
- promoted target hash mismatch
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/b910e9db9eb106bc.
Report an issue: GitHub.