jdx/mise · warning · eyre::Report
receipt target inventory is incomplete or duplicated
Error message
receipt target inventory is incomplete or duplicated
What it means
The receipt's classified artifact lists (apps, binaries, fonts, completions) are cross-checked against receipt.targets: the expected set must be non-empty, the deduplicated target-record map must equal receipt.targets in size (no duplicate paths), the record count must equal the expected set size (every classified path has exactly one record), and every metadata_only_apps entry must appear in apps. Any inconsistency means the receipt is internally incomplete or duplicated, so the prune is refused.
Solutions
- Reinstall the cask with the current mise to regenerate a self-consistent receipt, then prune.
- Inspect `<Caskroom>/<token>/<version>/.mise-cask.toml` for duplicate or missing target entries if manual repair is acceptable.
- If it reproduces on a fresh install, file a mise bug with the receipt contents.
Defensive patterns
Strategy: validation
Validate before calling
// Mirror the receipt cross-check before planning a prune
use std::collections::{BTreeMap, BTreeSet};
fn inventory_consistent(r: &CaskReceipt) -> bool {
let expected: BTreeSet<_> = r.apps.iter().chain(&r.binaries).chain(&r.fonts).chain(&r.completions).cloned().collect();
let records: BTreeMap<_, _> = r.targets.iter().map(|t| (t.path.clone(), t)).collect();
!expected.is_empty()
&& records.len() == r.targets.len()
&& records.len() == expected.len()
&& r.metadata_only_apps.iter().all(|p| r.apps.contains(p))
} Try / catch
Wrap validate_cask_prune_candidate in `if let Err(reason)` and record a skip; treat any inconsistency as 'receipt unusable — reinstall to regenerate'.
Prevention
- Regenerate receipts by reinstalling after mise version changes instead of pruning old receipts.
- Never hand-edit receipt TOML; a single duplicate path invalidates pruning.
When it happens
Trigger: A receipt where the same path appears twice in targets; a classified path (in apps/binaries/fonts/completions) with no corresponding target record; an empty artifact set; a metadata_only_apps path not listed in apps. Produced by receipt-writer bugs or a corrupted `.mise-cask.toml`.
Common situations: Receipts written by an older/newer mise with a different layout; truncated or corrupt TOML after a crash mid-write; hand-edited receipts.
Related errors
- artifact target has changed
- metadata-only app ownership cannot be proven safely during…
- ownership receipt has changed
- receipt is not marked safe for direct-artifact pruning
- receipt target inventory contains an unclassified path
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/bcce9541b7eb9bb6.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask.rs:7283
.map(|record| (record.path.clone(), record))
.collect::<BTreeMap<_, _>>();
let expected = receipt
.apps
.iter()
.chain(&receipt.binaries)
.chain(&receipt.fonts)
.chain(&receipt.completions)
.cloned()
.collect::<BTreeSet<_>>();
if expected.is_empty()
|| records.len() != receipt.targets.len()
|| records.len() != expected.len()
|| receipt
.metadata_only_apps
.iter()
.any(|path| !receipt.apps.contains(path))
{
bail!("receipt target inventory is incomplete or duplicated");
}
if records.keys().any(|path| !expected.contains(path)) {
bail!("receipt target inventory contains an unclassified path");
}
for path in &receipt.apps {
let record = records
.get(path)
.ok_or_else(|| eyre!("missing app target record"))?;
if record.fingerprint.kind != CaskTargetKind::Directory
|| !allowed_appdir_roots()?
.iter()
.any(|root| path_is_below(path, root))
|| !path.file_name().is_some_and(|name| {
staged_app_matches_target(record, &candidate.version_dir.join(name))
})
{
bail!(View on GitHub (pinned to 6f52dcdf99)