xai-org/grok-build · error
daemon RemoveWorktree failed: {e}
Error message
daemon RemoveWorktree failed: {e} What it means
remove_nfs_worktree first asks the grove daemon to remove the worktree via client.remove_worktree. If the daemon accepts the ping but the RemoveWorktree RPC returns an error, this wraps and surfaces it as 'daemon RemoveWorktree failed', aborting the local remove path.
Source
Thrown at crates/codegen/xai-fast-worktree/src/nfs/remove.rs:42
if lookup_from_markers(worktree_path).is_none() {
bail!(
"{} is a live grove mount without a backing marker; refusing rm -rf",
worktree_path.display()
);
}
} else if dest_is_mountpoint(worktree_path) || lookup_nfs_meta(worktree_path).is_none() {
return Ok(None);
}
remove_nfs_worktree(worktree_path)
}
fn remove_nfs_worktree(worktree_path: &Path) -> Result<Option<RemoveReport>> {
let opts = nfs_opts_from_env_and_meta(None);
let client = NfsWorktreeClient::from_opts(&opts);
if client.ping() {
match client.remove_worktree(worktree_path, false) {
Ok(()) => return report_after_daemon_unmount(worktree_path),
Err(e) => {
bail!("daemon RemoveWorktree failed: {e}");
}
}
}
if dest_is_mountpoint(worktree_path) {
if lookup_from_markers(worktree_path).is_none() {
bail!(
"{} is still a mountpoint without a grove marker; refusing umount/rm",
worktree_path.display()
);
}
plain_umount(worktree_path)?;
}
if !super::dest_is_known_unmounted(worktree_path) {
bail!(
"unmount of {} could not be verified (still mounted or mount table \
inconclusive); retaining backing and pin",
worktree_path.display()
);View on GitHub (pinned to bc7f02eddd)
Solutions
- Inspect the inner error (source chain) — usually EBUSY/permission — and close processes using the mount, then retry
- Check daemon logs for the RemoveWorktree failure reason
- Restart the daemon to clear stale state, then retry try_nfs_remove
- Fall back to the manual path: umount the dest, verify unmounted, then remove backing yourself
Example fix
// before
try_nfs_remove(&path)?;
// after
if let Err(e) = try_nfs_remove(&path) {
eprintln!("daemon remove failed: {e:#}");
Command::new("umount").arg(&path).status()?;
// verify unmounted, then remove backing dir manually
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure no processes hold the mount before daemon removal
let busy = Command::new("fuser").arg("-m").arg(&path)
.stdout(Stdio::null()).status().map(|s| s.success());
if busy == Ok(true) { eprintln!("mount is busy; close processes first"); } Try / catch
match client.remove_worktree(worktree_path, false) {
Ok(()) => {}
Err(e) => {
eprintln!("RemoveWorktree failed: {e:#}"); // inspect source chain for EBUSY/EACCES
// fall back to manual umount + verified removal
}
} Prevention
- Close editors/shells/cd'd processes inside the worktree before removal
- Run the remove as the same user as the daemon
- Keep daemon logs handy and inspect the anyhow source chain
When it happens
Trigger: Calling try_nfs_remove while the daemon is up but its remove_worktree fails: dest busy/EBUSY, backing dir missing, permission denied, worktree id lookup failed, or daemon-side unmount rejected.
Common situations: A process still holds files open under the mount (EBUSY); daemon lost track of the worktree after a config change; running the remove as a different user than the daemon.
Related errors
- e.error (daemon error message propagated via anyhow!)
- mount table inconclusive for {}; refusing remove
- invalid worktree id from dest: {worktree_id}
- pin delete requires grove
- invalid worktree id {:?}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/1b2e8065e9e9c1b9.
Report an issue: GitHub.