jdx/mise · error · eyre::Report

artifact target is now claimed by another cask: {}

Error message

artifact target is now claimed by another cask: {}

What it means

Before pruning a cask's artifacts, mise builds a claim map of every artifact target path from the receipts of all known casks (Homebrew-owned and mise-owned). If any target of the prune candidate is claimed by a receipt belonging to a different cask token, it bails — deleting would destroy the other cask's artifact. This is an ownership guard, not a filesystem error.

Source

Thrown at src/system/packages/brew/cask.rs:6995

            let version = version?;
            if !version.file_type()?.is_dir()
                || version.file_name().to_string_lossy().starts_with('.')
            {
                continue;
            }
            if let Some(receipt) = read_receipt(&version.path())? {
                for target in receipt.targets {
                    claims.entry(target.path).or_default().insert(token.clone());
                }
            }
        }
    }
    for target in &candidate.receipt.targets {
        if claims
            .get(&target.path)
            .is_some_and(|tokens| tokens.iter().any(|token| token != &candidate.token))
        {
            bail!(
                "artifact target is now claimed by another cask: {}",
                target.path.display()
            );
        }
    }
    Ok(())
}

fn validate_cask_prune_candidate(candidate: &CaskPruneCandidate) -> Result<()> {
    if homebrew_metadata_present(&candidate.token) {
        bail!("Homebrew now owns this cask");
    }
    let receipt = &candidate.receipt;
    if read_receipt(&candidate.version_dir)?.as_ref() != Some(receipt) {
        bail!("ownership receipt has changed");
    }
    if receipt.schema_version != 3 || !receipt.prune_safe || !receipt.pkg_ids.is_empty() {
        bail!("receipt is not marked safe for direct-artifact pruning");

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Prefer `brew uninstall --cask <token>` for the cask you want removed — Homebrew resolves shared artifacts itself
  2. Inspect receipts to see who claims the path: look under the caskroom metadata/receipt dirs for both tokens before pruning
  3. Remove the stale receipt of the cask you no longer have, so its false claim disappears, then retry the prune
  4. Keep both casks if they genuinely share the artifact
Defensive patterns

Strategy: validation

Validate before calling

// Before pruning, confirm no other cask receipt claims the same targets:
fn target_unclaimed(target: &std::path::Path, claims: &std::collections::HashMap<std::path::PathBuf, std::collections::BTreeSet<String>>, my_token: &str) -> bool {
    claims
        .get(target)
        .map(|tokens| tokens.iter().all(|t| t == my_token))
        .unwrap_or(true)
}

Try / catch

match validate_prune_targets(&candidate) {
    Ok(()) => prune(),
    Err(e) if e.to_string().contains("claimed by another cask") => {
        warn!("artifact shared with another cask; deferring to brew uninstall");
        Ok(())
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Two casks' receipts record the same target path (shared bundle name, nested .app inside another cask's bundle, or a moved receipt), and one of them is being pruned/uninstalled via mise.

Common situations: Casks that install sub-apps into another cask's bundle directory; a cask reinstalled under a different token or renamed upstream; stale receipts from manually copied .app bundles.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/739397d4f50bf4cf. Report an issue: GitHub.