xai-org/grok-build · error
failed to delete BTRFS snapshot at {}: {}
Error message
failed to delete BTRFS snapshot at {}: {} What it means
`delete_snapshot` runs `btrfs subvolume delete <path>`; if the command exits non-zero, it bails with this message including the path and btrfs's stderr. The btrfs tool refused to delete the subvolume snapshot.
Source
Thrown at crates/codegen/xai-fast-worktree/src/btrfs/snapshot.rs:331
}
/// Delete a BTRFS subvolume/snapshot.
pub fn delete_snapshot(path: &Path) -> Result<()> {
let mut cmd = Command::new("btrfs");
xai_tty_utils::detach_std_command(&mut cmd);
cmd.stdin(Stdio::null());
// Pass the path as OsStr (no lossy `to_str`) so a non-UTF-8 path can never
// silently collapse to "." and delete the current directory's subvolume.
let output = cmd
.arg("subvolume")
.arg("delete")
.arg(path)
.output()
.with_context(|| "failed to execute btrfs subvolume delete command")?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
bail!(
"failed to delete BTRFS snapshot at {}: {}",
path.display(),
stderr.trim()
);
}
Ok(())
}
/// Validate that `snapshot_path` is a safe target for a privileged
/// `btrfs subvolume delete`.
///
/// Guards against destroying an arbitrary subvolume (e.g. the live source repo,
/// or another session/user's snapshot) via a stale, confused, or planted
/// symlink or `*.btrfs-meta.json` entry. Returns `true` only when the path:
/// - contains no `..` component,
/// - is not itself a symlink (`lstat`, so a planted symlink can't redirect the
/// delete to a subvolume elsewhere),View on GitHub (pinned to bc7f02eddd)
Solutions
- Read the stderr in the error message for btrfs's exact reason ('not a subvolume', 'device busy', 'permission denied').
- Ensure nothing uses the snapshot: unmount it, stop containers/worktrees holding it open, then retry.
- Verify the path is actually a btrfs subvolume with `btrfs subvolume show <path>`; delete plain directories with `rm -rf` instead.
- Run with sufficient privileges and confirm the `btrfs` tool exists in the environment.
- For recreation flows, handle this error by cleaning dependents first rather than retrying the same call blindly.
Example fix
// before
delete_snapshot(Path::new("/mnt/btrfs/snapshots/wt-42"))?; // busy: still mounted
// after
// ensure the snapshot is not mounted, then retry
run("umount /mnt/btrfs/snapshots/wt-42");
delete_snapshot(Path::new("/mnt/btrfs/snapshots/wt-42"))?;
Defensive patterns
Strategy: try-catch
Validate before calling
use std::process::Command;
use std::path::Path;
fn snapshot_deletable(p: &Path) -> bool {
// must be a btrfs subvolume and not currently mounted
let is_subvol = Command::new("btrfs").args(["subvolume", "show"]).arg(p)
.output().map(|o| o.status.success()).unwrap_or(false);
let not_mounted = !std::fs::read_to_string("/proc/mounts")
.map(|m| m.contains(&p.to_string_lossy().to_string())).unwrap_or(true);
is_subvol && not_mounted
} Try / catch
match delete_snapshot(&path) {
Err(e) if e.to_string().contains("failed to delete BTRFS snapshot") => {
eprintln!("btrfs delete refused: {e}");
// stop consumers / unmount, then retry once
}
r => r?,
} Prevention
- Unmount snapshots and stop worktrees/containers using them before deletion
- Confirm the path is a subvolume (btrfs subvolume show) before deleting
- Run with root or CAP_SYS_ADMIN
- Retry deletion after consumers release the path rather than immediately
When it happens
Trigger: Calling `delete_snapshot` (directly or from `create_snapshot_with_symlink`'s recreate path) when the path isn't a btrfs subvolume, is busy (open files, mounted), or the user lacks privileges.
Common situations: Snapshot still mounted or referenced by a running worktree/container; target is a plain directory, not a subvolume; running without root/CAP_SYS_ADMIN; filesystem errors or read-only subvolume; `btrfs` binary missing in containers.
Related errors
- failed to create BTRFS snapshot from {} to {}: {}
- refusing to delete pre-existing snapshot {}: outside grok-ma
- overlay mount delegation not supported by this delegate
- overlay unmount delegation not supported by this delegate
- refusing to delete pre-existing snapshot {}: its metadata ta
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/7f555ee061eea125.
Report an issue: GitHub.