jdx/mise · error

brew-cask: unsupported generic artifact type: {}

Error message

brew-cask: unsupported generic artifact type: {}

What it means

When copying a generic cask artifact into protected staging (copy_cask_artifact_at), mise handles exactly two source kinds: directories (opened via openat in the branch above) and regular files (opened with O_NOFOLLOW|O_CREAT|O_EXCL and copied byte-for-byte). Any other file type — symlink, FIFO, socket, device — falls into the else branch and is refused with the source path.

Source

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

            copy_cask_artifact_at(&entry.path(), &fd, &entry.file_name())?;
        }
        nix::sys::stat::fchmod(&fd, mode)?;
    } else if metadata.is_file() {
        let destination = nix::fcntl::openat(
            parent,
            name,
            nix::fcntl::OFlag::O_WRONLY
                | nix::fcntl::OFlag::O_CREAT
                | nix::fcntl::OFlag::O_EXCL
                | nix::fcntl::OFlag::O_NOFOLLOW,
            nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR,
        )?;
        let mut source = std::fs::File::open(from)?;
        let mut destination = std::fs::File::from(destination);
        copy_file_contents(&mut source, &mut destination)?;
        nix::sys::stat::fchmod(&destination, mode)?;
    } else {
        bail!(
            "brew-cask: unsupported generic artifact type: {}",
            from.display()
        );
    }
    Ok(())
}

#[cfg(all(unix, target_os = "macos"))]
fn copy_file_contents(from: &mut std::fs::File, to: &mut std::fs::File) -> Result<()> {
    use std::os::fd::AsRawFd;

    // SAFETY: both descriptors remain open for the call and fcopyfile does not
    // retain them. A null state requests the default copyfile state.
    let result = unsafe {
        nix::libc::fcopyfile(
            from.as_raw_fd(),
            to.as_raw_fd(),
            std::ptr::null_mut(),

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. If you maintain the cask, materialize symlinks as real files before packaging (cp -L), or point the artifact stanza at the real file
  2. Otherwise report the cask to its tap — mise intentionally refuses to copy special files into protected locations

Example fix

# before (packaging)
cd dist && zip -r tool.zip .          # bin/tool is a symlink -> tool-1.2.3

# after
cp -L bin/tool bin/tool.real && rm bin/tool && mv bin/tool.real bin/tool
cd dist && zip -r tool.zip .          # bin/tool is a regular file
Defensive patterns

Strategy: validation

Validate before calling

// Tap authors: assert artifact sources are regular files/dirs before publishing
let ft = std::fs::symlink_metadata(&artifact_source)?.file_type();
assert!(ft.is_file() || ft.is_dir(), "generic artifact must be a real file or dir, got symlink/special");

Type guard

fn is_copyable_artifact(p: &Path) -> bool {
    p.symlink_metadata().map_or(false, |m| m.is_file() || m.is_dir())
}

Try / catch

Catch 'unsupported generic artifact type' and report that the cask ships a symlink/special file as its artifact; remediation is repackaging the tap, so fail with a clear pointer rather than retrying.

Prevention

When it happens

Trigger: A cask's generic artifact source inside the archive is a symlink or other special file rather than a real file or directory — e.g. a tap zipping a build directory where the shipped binary is a relative symlink to a versioned file.

Common situations: Hand-built internal casks that zip directories containing symlinks; artifacts whose 'binary' entry is a link into another part of the archive.

Related errors


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