xai-org/grok-build · error · anyhow::Error
e.error (daemon error message propagated via anyhow!)
Error message
e.error (daemon error message propagated via anyhow!)
What it means
Inside query_phase, when the daemon answers `Response::Err(e)`, the daemon's error string `e.error` is wrapped via `anyhow!` into an `NfsTryError::Other`. The resulting message is the daemon-side explanation (e.g. unknown worktree, declined, storage full), not a client-side message.
Source
Thrown at crates/codegen/xai-fast-worktree/src/nfs/client.rs:230
v: PROTOCOL_VERSION,
worktree_id: worktree_id.to_owned(),
};
match self.call(&req, self.ping_timeout.max(QUERY_PHASE_MIN_TIMEOUT)) {
Ok(Response::Ok(body)) => Ok(QuerySnapshot {
phase: body.create_phase,
declined: body.declined,
storage_full: body.storage_full,
unknown: false,
mount: body.mount,
}),
Ok(Response::Err(e)) if e.error.contains("unknown worktree_id") => Ok(QuerySnapshot {
phase: None,
declined: None,
storage_full: false,
unknown: true,
mount: None,
}),
Ok(Response::Err(e)) => Err(NfsTryError::Other(anyhow!(e.error))),
Err(e) => Err(NfsTryError::Other(e)),
}
}
pub fn cancel_worktree_create(&self, worktree_id: &str) -> Result<(), anyhow::Error> {
if !self.ping() {
anyhow::bail!("grove daemon unreachable");
}
let req = Request::CancelWorktreeCreate {
v: PROTOCOL_VERSION,
worktree_id: worktree_id.to_owned(),
};
match self.call(&req, REMOVE_RPC_TIMEOUT) {
Ok(Response::Ok(_)) => Ok(()),
Ok(Response::Err(e)) => Err(anyhow!(e.error)),
Err(e) => Err(e),
}
}View on GitHub (pinned to bc7f02eddd)
Solutions
- Read the propagated daemon message to identify the specific cause (unknown/declined/storage_full/mount)
- Re-check the worktree_id used in the request matches one the daemon knows
- Check daemon availability and restart state; retry creation if state was lost
- Free NFS storage if the message indicates the export is full
Example fix
// handle daemon rejection explicitly
match client.query_phase(&id) {
Ok(reply) => { /* use reply.phase */ }
Err(NfsTryError::Other(e)) => eprintln!("daemon rejected: {e}"),
Err(e) => eprintln!("transport error: {e}"),
} Defensive patterns
Strategy: type-guard
Validate before calling
// Prefer structured reply over string matching:
let reply = client.query_phase(&id)?;
if reply.unknown {
// daemon does not know this id — recreate before proceeding
}
if reply.storage_full {
// free space on the NFS export before retrying
} Type guard
fn daemon_rejection(err: &NfsTryError) -> Option<String> {
match err {
NfsTryError::Other(e) => Some(e.to_string()),
_ => None,
}
} Try / catch
match client.query_phase(&id) {
Ok(r) => handle(r),
Err(NfsTryError::Other(e)) => eprintln!("daemon error: {e}"),
Err(e) => return Err(e.into()),
} Prevention
- Check reply flags (unknown/declined/storage_full) instead of parsing error strings
- Persist worktree ids so a lost reply can be re-queried safely
- Monitor NFS export capacity before large creates
- Keep client and daemon protocol versions in sync
When it happens
Trigger: Calling query_phase while the daemon rejects the request: worktree id unknown to the daemon, creation declined by policy, NFS storage full, or a mount error reported by the daemon.
Common situations: Polling after a lost reply for a create that never registered; daemon restarted losing in-memory worktree state; NFS export hitting capacity; version mismatch between client and daemon causing rejected requests.
Related errors
- daemon RemoveWorktree failed: {e}
- invalid worktree id from dest: {worktree_id}
- preserve on a projected Grove source is not supported
- ACP error: {err}
- OUT_OF_DISK_CONTEXT
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/9d1db6c5d5c896bf.
Report an issue: GitHub.