jdx/mise · error

receipt target inventory contains an unclassified path

Error message

receipt target inventory contains an unclassified path

What it means

During cask prune validation, mise maps every receipt target path into a set and cross-checks it against the expected 'standard' targets (apps, binaries, fonts, completions). If a target record's path is not in any of those categories, the receipt contains a target the pruner cannot classify, and it bails rather than delete files it cannot attribute safely.

Solutions

  1. Reinstall the cask via mise (uninstall + install) so the receipt is regenerated with a fully classified target set
  2. Open the version's receipt file and check which target path is unclassified relative to receipt.apps/binaries/fonts/completions; correct the categorization or remove the stale entry
  3. Verify receipt.schema_version is 3 and the receipt was written by the current mise; regenerate otherwise
  4. Exclude that cask token from the prune plan; let brew own the artifact if it installs nonstandard targets

Example fix

// before: receipt targets include an unclassified helper
{"targets": [{"path": "/Applications/Foo.app"}, {"path": "/usr/local/helper"}], "apps": ["/Applications/Foo.app"], ...}
// after: reinstall to regenerate receipt with all targets classified
mise uninstall brew-cask:foo && mise install brew-cask:foo
Defensive patterns

Strategy: validation

Validate before calling

// ensure every target path is classified before pruning
fn all_targets_classified(receipt: &CaskReceipt) -> bool {
    let expected: BTreeSet<_> = receipt.standard_targets().collect();
    receipt.targets.iter().all(|t| expected.contains(&t.path))
}
if !all_targets_classified(&candidate.receipt) { /* skip or reinstall cask */ }

Type guard

fn has_only_standard_targets(receipt: &CaskReceipt) -> bool {
    let expected: BTreeSet<_> = receipt.standard_targets().collect();
    receipt.targets.iter().all(|t| expected.contains(&t.path))
}

Try / catch

match apply_cask_prune_plan_in(&plan) {
    Ok(removed) => info!("pruned {removed} casks"),
    Err(e) if e.to_string().contains("unclassified path") => {
        warn!("cask has unclassifiable targets; manage via brew instead: {e:#}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling cask_prune_plan_from_tokens or apply_cask_prune_plan_in with a receipt whose targets list includes a path outside standard_targets() — e.g. a target recorded under a category (apps/binaries/fonts/completions) it does not belong to, or an extra target written by a nonstandard install path.

Common situations: A cask that installs extras (pkg payloads, helper tools in unusual locations) recorded in targets but never listed in a category; receipts migrated from an older schema; corrupted or manually modified receipt files.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/9bc2492d677c045f. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/state.rs:1061

    }
    let records = receipt
        .targets
        .iter()
        .map(|record| (record.path.clone(), record))
        .collect::<BTreeMap<_, _>>();
    let expected = receipt.standard_targets().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!(
                "app target is outside an allowed Applications directory: {}",
                path.display()
            );

View on GitHub (pinned to 533346cc37)