xai-org/grok-build · error

pin delete requires grove

Error message

pin delete requires grove

What it means

delete_pin_ref_gated is the non-grove (feature-gated) stub for removing a pin reference. In this build, pin deletion is only implemented through the grove daemon, so the function unconditionally bails: any caller attempting a pin delete without grove support compiled in / without the daemon gets this error.

Source

Thrown at crates/codegen/xai-fast-worktree/src/nfs/liveness.rs:529

    let mut buf = Vec::new();
    Read::take(file, MAX_MARKER_BYTES.saturating_add(1))
        .read_to_end(&mut buf)
        .ok()?;
    if buf.len() as u64 > MAX_MARKER_BYTES {
        return None;
    }
    Some(buf)
}
fn pin_exists(source: &Path, worktree_id: &str) -> Result<bool> {
    {
        let _ = (source, worktree_id);
        Ok(false)
    }
}
fn delete_pin_ref_gated(source: &Path, worktree_id: &str) -> Result<()> {
    {
        let _ = (source, worktree_id);
        anyhow::bail!("pin delete requires grove")
    }
}
#[cfg(feature = "metadata")]
pub fn identities_from_worktree_records(recs: &[crate::db::WorktreeRecord]) -> Vec<NfsIdentity> {
    recs.iter()
        .filter(|r| crate::worktree::is_grove_strategy(&r.creation_mode))
        .map(|r| {
            let grove = r
                .metadata
                .as_ref()
                .and_then(|m| m.get("grove").or_else(|| m.get("nfs")));
            let backing = grove
                .and_then(|n| n.get("backing"))
                .and_then(|b| b.as_str())
                .filter(|s| !s.is_empty())
                .map(PathBuf::from);
            let pin = grove
                .and_then(|n| n.get("source_pin"))

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Ensure pin deletion goes through the grove daemon path (gate gc_orphan_pins on grove strategy, e.g. filter records with is_grove_strategy)
  2. Compile/enable the grove feature so the real implementation is used instead of the stub
  3. Skip pin deletion for non-grove worktrees instead of calling the gated function

Example fix

// before
for id in orphans {
    delete_pin_ref_gated(&source, id)?;
}
// after
for rec in recs.iter().filter(|r| crate::worktree::is_grove_strategy(&r.creation_mode)) {
    delete_pin_ref_gated(&rec.source, &rec.worktree_id)?;
}
Defensive patterns

Strategy: fallback

Validate before calling

#[cfg(feature = "metadata")]
let is_grove = recs.iter().any(|r| crate::worktree::is_grove_strategy(&r.creation_mode));
if !is_grove { return Ok(()); } // skip pin deletion

Try / catch

match delete_pin_ref_gated(&source, id) {
    Err(e) if e.to_string() == "pin delete requires grove" => {
        // skip or route through the grove daemon path
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling gc_orphan_pins (which invokes delete_pin_ref_gated) on a code path that is not gated to grove-managed worktrees — i.e. trying to delete an NFS pin reference outside the grove-managed flow.

Common situations: Running an orphan-pin GC while worktrees were created with a non-grove creation_mode; a build without the metadata/grove gating reaching the stub; callers porting old pin-cleanup code to the new gated API.

Related errors


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