jdx/mise · error

brew-cask: unsupported target type

Error message

brew-cask: unsupported target type '{}'

What it means

cask_target_fingerprint computes a content identity for an installed cask artifact: a digest for directories, a kind marker for files/symlinks. If the path is neither a directory, file, nor symlink (e.g. a device, socket, or fifo), mise has no fingerprinting strategy and refuses rather than produce an unsound identity used for adoption/prune safety decisions.

Solutions

  1. Inspect the path (`ls -l`, `stat`) and remove or replace the special file with the expected artifact.
  2. Reinstall the cask (`brew reinstall --cask <token>`) so Homebrew recreates the correct file/directory.
  3. If the special file is intentional, exclude it from cask artifact targets rather than trying to fingerprint it.

Example fix

// before: a fifo where the app bundle belongs
$ ls -l /Applications/MyApp.app
prw-r--r--  MyApp.app

// after
$ rm /Applications/MyApp.app && brew reinstall --cask myapp
Defensive patterns

Strategy: validation

Validate before calling

let ft = std::fs::symlink_metadata(path)?.file_type();
if !(ft.is_dir() || ft.is_file() || ft.is_symlink()) {
    // special file at target path; resolve before installing/pruning
}

Type guard

fn is_fingerprintable(p: &Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| {
        let ft = m.file_type();
        ft.is_dir() || ft.is_file() || ft.is_symlink()
    }).unwrap_or(false)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("unsupported target type") => {
        remove_special_file(path)?; reinstall_cask(token)
    }
    r => r,
}

Prevention

When it happens

Trigger: install_app or validate_adoptable_apps (and CaskTargetRecord / cask_target_record_matches / staged_target_matches) fingerprint a target path whose metadata.is_dir() is false and whose file type is neither file nor symlink — e.g. a socket, fifo, or device node present at an artifact target path.

Common situations: A cask's app target path was replaced by a Unix socket or FIFO by some tool; a broken filesystem state or unusual mount left a special file where a regular artifact should live.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        let target = std::fs::read_link(path)?;
        return Ok(CaskTargetFingerprint {
            kind: CaskTargetKind::Symlink,
            digest: hex::encode(Sha256::digest(target.as_os_str().as_encoded_bytes())),
        });
    }
    if metadata.is_file() {
        return Ok(CaskTargetFingerprint {
            kind: CaskTargetKind::File,
            digest: hash::file_hash_sha256(path, None)?,
        });
    }
    if metadata.is_dir() {
        return Ok(CaskTargetFingerprint {
            kind: CaskTargetKind::Directory,
            digest: cask_directory_digest(path)?,
        });
    }
    bail!("brew-cask: unsupported target type '{}'", path.display())
}

/// Content identity intentionally excludes timestamps, ownership, and modes.
/// It hashes stable relative paths, entry kinds, file bytes, and link targets
/// without following symlinks.
pub(super) fn cask_directory_digest(root: &Path) -> Result<String> {
    let mut entries = WalkDir::new(root)
        .follow_links(false)
        .into_iter()
        .collect::<std::result::Result<Vec<_>, _>>()?;
    entries.sort_by(|a, b| a.path().cmp(b.path()));
    let mut digest = Sha256::new();
    for entry in entries {
        let path = entry.path();
        let relative = path.strip_prefix(root)?;
        if relative.as_os_str().is_empty() {
            continue;
        }

View on GitHub (pinned to 533346cc37)