{"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":1964,"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":1946,"sourceCodeEnd":1982,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L1946-L1982","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-built internal casks that zip directories containing symlinks; artifacts whose 'binary' entry is a link into another part of the archive.","solutions":["If you maintain the cask, materialize symlinks as real files before packaging (cp -L), or point the artifact stanza at the real file","Otherwise report the cask to its tap — mise intentionally refuses to copy special files into protected locations"],"exampleFix":"# before (packaging)\ncd dist && zip -r tool.zip .          # bin/tool is a symlink -> tool-1.2.3\n\n# after\ncp -L bin/tool bin/tool.real && rm bin/tool && mv bin/tool.real bin/tool\ncd dist && zip -r tool.zip .          # bin/tool is a regular file","handlingStrategy":"validation","validationCode":"// Tap authors: assert artifact sources are regular files/dirs before publishing\nlet ft = std::fs::symlink_metadata(&artifact_source)?.file_type();\nassert!(ft.is_file() || ft.is_dir(), \"generic artifact must be a real file or dir, got symlink/special\");","typeGuard":"fn is_copyable_artifact(p: &Path) -> bool {\n    p.symlink_metadata().map_or(false, |m| m.is_file() || m.is_dir())\n}","tryCatchPattern":"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.","preventionTips":["Dereference symlinks (cp -L) when zipping cask payloads","Point artifact stanzas at real files; let mise create any links via proper binary stanza handling"],"tags":["homebrew","cask","artifact","file-type","mise"],"backgroundTag":"unsupported-file-type","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}