{"record":{"id":"9bc2492d677c045f","repo":"jdx/mise","slug":"receipt-target-inventory-contains-an-unclassified-9bc249","errorCode":null,"errorMessage":"receipt target inventory contains an unclassified path","messagePattern":"receipt target inventory contains an unclassified path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/state.rs","lineNumber":1061,"sourceCode":"    }\n    let records = receipt\n        .targets\n        .iter()\n        .map(|record| (record.path.clone(), record))\n        .collect::<BTreeMap<_, _>>();\n    let expected = receipt.standard_targets().cloned().collect::<BTreeSet<_>>();\n    if expected.is_empty()\n        || records.len() != receipt.targets.len()\n        || records.len() != expected.len()\n        || receipt\n            .metadata_only_apps\n            .iter()\n            .any(|path| !receipt.apps.contains(path))\n    {\n        bail!(\"receipt target inventory is incomplete or duplicated\");\n    }\n    if records.keys().any(|path| !expected.contains(path)) {\n        bail!(\"receipt target inventory contains an unclassified path\");\n    }\n\n    for path in &receipt.apps {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing app target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Directory\n            || !allowed_appdir_roots()?\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !path.file_name().is_some_and(|name| {\n                staged_app_matches_target(record, &candidate.version_dir.join(name))\n            })\n        {\n            bail!(\n                \"app target is outside an allowed Applications directory: {}\",\n                path.display()\n            );","sourceCodeStart":1043,"sourceCodeEnd":1079,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/state.rs#L1043-L1079","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reinstall the cask via mise (uninstall + install) so the receipt is regenerated with a fully classified target set","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","Verify receipt.schema_version is 3 and the receipt was written by the current mise; regenerate otherwise","Exclude that cask token from the prune plan; let brew own the artifact if it installs nonstandard targets"],"exampleFix":"// before: receipt targets include an unclassified helper\n{\"targets\": [{\"path\": \"/Applications/Foo.app\"}, {\"path\": \"/usr/local/helper\"}], \"apps\": [\"/Applications/Foo.app\"], ...}\n// after: reinstall to regenerate receipt with all targets classified\nmise uninstall brew-cask:foo && mise install brew-cask:foo","handlingStrategy":"validation","validationCode":"// ensure every target path is classified before pruning\nfn all_targets_classified(receipt: &CaskReceipt) -> bool {\n    let expected: BTreeSet<_> = receipt.standard_targets().collect();\n    receipt.targets.iter().all(|t| expected.contains(&t.path))\n}\nif !all_targets_classified(&candidate.receipt) { /* skip or reinstall cask */ }","typeGuard":"fn has_only_standard_targets(receipt: &CaskReceipt) -> bool {\n    let expected: BTreeSet<_> = receipt.standard_targets().collect();\n    receipt.targets.iter().all(|t| expected.contains(&t.path))\n}","tryCatchPattern":"match apply_cask_prune_plan_in(&plan) {\n    Ok(removed) => info!(\"pruned {removed} casks\"),\n    Err(e) if e.to_string().contains(\"unclassified path\") => {\n        warn!(\"cask has unclassifiable targets; manage via brew instead: {e:#}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Avoid casks that install nonstandard extras if you rely on direct-artifact pruning; prefer brew for those","Check receipt targets against apps/binaries/fonts/completions before planning a prune","Regenerate receipts via reinstall after schema or mise version changes","Treat 'unclassified path' as a signal the cask should be brew-managed, not mise-pruned"],"tags":["brew","cask","validation","receipt"],"backgroundTag":"schema-validation-failed","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}