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.

Solutions

  1. Read the stderr in the error message for btrfs's exact reason ('not a subvolume', 'device busy', 'permission denied').
  2. Ensure nothing uses the snapshot: unmount it, stop containers/worktrees holding it open, then retry.
  3. Verify the path is actually a btrfs subvolume with `btrfs subvolume show <path>`; delete plain directories with `rm -rf` instead.
  4. Run with sufficient privileges and confirm the `btrfs` tool exists in the environment.
  5. 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

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


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/7f555ee061eea125. Report an issue: GitHub.

Appendix: 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)