{"record":{"id":"220d94ab974e32b5","repo":"jdx/mise","slug":"brew-cask-unsupported-generic-artifact-type","errorCode":null,"errorMessage":"brew-cask: unsupported generic artifact type: {}","messagePattern":"brew-cask: unsupported generic artifact type: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":2090,"sourceCode":"            copy_cask_artifact_at(&entry.path(), &fd, &entry.file_name())?;\n        }\n        nix::sys::stat::fchmod(&fd, mode)?;\n    } else if metadata.is_file() {\n        let destination = nix::fcntl::openat(\n            parent,\n            name,\n            nix::fcntl::OFlag::O_WRONLY\n                | nix::fcntl::OFlag::O_CREAT\n                | nix::fcntl::OFlag::O_EXCL\n                | nix::fcntl::OFlag::O_NOFOLLOW,\n            nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR,\n        )?;\n        let mut source = std::fs::File::open(from)?;\n        let mut destination = std::fs::File::from(destination);\n        copy_file_contents(&mut source, &mut destination)?;\n        nix::sys::stat::fchmod(&destination, mode)?;\n    } else {\n        bail!(\n            \"brew-cask: unsupported generic artifact type: {}\",\n            from.display()\n        );\n    }\n    Ok(())\n}\n\n#[cfg(all(unix, target_os = \"macos\"))]\nfn copy_file_contents(from: &mut std::fs::File, to: &mut std::fs::File) -> Result<()> {\n    use std::os::fd::AsRawFd;\n\n    // SAFETY: both descriptors remain open for the call and fcopyfile does not\n    // retain them. A null state requests the default copyfile state.\n    let result = unsafe {\n        nix::libc::fcopyfile(\n            from.as_raw_fd(),\n            to.as_raw_fd(),\n            std::ptr::null_mut(),","sourceCodeStart":2072,"sourceCodeEnd":2108,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L2072-L2108","documentation":"Thrown by copy_cask_artifact_at, the recursive copier used for cask `artifact` (generic) stanzas. It only knows three entry kinds: symlinks (recreated with symlinkat), directories (recreated with mkdirat and walked), and regular files (copied with openat O_EXCL then fchmod). Anything else staged at the printed path — a FIFO, unix socket, or device node — hits this bail and the install aborts.","triggerScenarios":"Installing a cask whose downloaded/staged archive contains a special file (mkfifo-created entry, socket, device node) anywhere in the artifact tree that copy_cask_artifact recurses into; reachable whenever the generic artifact source is copied into the target parent.","commonSituations":"Hand-built or repackaged cask archives that tar'd up a live directory containing sockets/fifos; archives produced on Linux with mknod entries; casks that worked under Homebrew's ruby installer because ruby's FileUtils skipped such entries silently.","solutions":["Inspect the printed staged path with `ls -l` / `stat` to identify the non-regular entry (fifo, socket, device)","Rebuild or re-download the cask payload shipping only regular files, directories, and symlinks","If you control the cask, drop the special file from the archive and create it at runtime via the tool itself or a postflight step","Report the cask token to its tap if the archive is upstream-broken"],"exampleFix":"# before: archive was built from a live dir and contains a socket\n$ tar -cf app.tar util/            # util/run.sock included\n\n# after: package regular files and symlinks only\n$ find util \\( -type f -o -type l \\) | tar -cf app.tar -T -","handlingStrategy":"validation","validationCode":"// Before installing, walk the staged artifact tree and reject non-regular entries.\nfn staged_tree_is_copyable(root: &std::path::Path) -> std::io::Result<()> {\n    let meta = root.symlink_metadata()?;\n    let ft = meta.file_type();\n    if ft.is_symlink() || ft.is_file() {\n        return Ok(());\n    }\n    if !ft.is_dir() {\n        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput,\n            format!(\"unsupported artifact type: {}\", root.display())));\n    }\n    for entry in std::fs::read_dir(root)? {\n        staged_tree_is_copyable(&entry?.path())?;\n    }\n    Ok(())\n}","typeGuard":"fn is_supported_artifact_entry(ft: &std::fs::FileType) -> bool {\n    ft.is_file() || ft.is_dir() || ft.is_symlink()\n}","tryCatchPattern":null,"preventionTips":["Validate downloaded archives before staging: reject payloads containing sockets, fifos, or device nodes","Build archives from a manifest of files rather than by tarring live directories","Run a pre-install scan of the caskroom stage directory when integrating cask installs into automation"],"tags":["brew-cask","generic-artifact","file-type","fifo","homebrew"],"backgroundTag":"unsupported-file-type","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}