{"record":{"id":"c86595f7df08923c","repo":"Hmbown/CodeWhale","slug":"fleet-file-must-be-a-regular-non-hard-linked-file","errorCode":null,"errorMessage":"Fleet file must be a regular, non-hard-linked file","messagePattern":"Fleet file must be a regular, non-hard-linked file","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/files.rs","lineNumber":134,"sourceCode":"        use std::os::fd::{AsRawFd, FromRawFd};\n        use std::os::unix::fs::MetadataExt;\n        // SAFETY: a pinned parent and validated basename; never follows links.\n        let fd = unsafe {\n            libc::openat(\n                self.directory.as_raw_fd(),\n                self.filename.as_ptr(),\n                flags | libc::O_NOFOLLOW | libc::O_CLOEXEC | libc::O_NONBLOCK,\n                0o600,\n            )\n        };\n        if fd < 0 {\n            return Err(io::Error::last_os_error());\n        }\n        // SAFETY: fd is freshly owned.\n        let file = unsafe { File::from_raw_fd(fd) };\n        let metadata = file.metadata()?;\n        if !metadata.is_file() || metadata.nlink() != 1 {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"Fleet file must be a regular, non-hard-linked file\",\n            ));\n        }\n        Ok(file)\n    }\n\n    pub(crate) fn publish(&self, bytes: &[u8]) -> io::Result<()> {\n        self.atomic_write(bytes, false)\n    }\n\n    pub(crate) fn replace(&self, bytes: &[u8]) -> io::Result<()> {\n        self.atomic_write(bytes, true)\n    }\n\n    fn atomic_write(&self, bytes: &[u8], replace: bool) -> io::Result<()> {\n        use std::os::fd::{AsRawFd, FromRawFd};\n        let temporary =","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/files.rs#L116-L152","documentation":"This error means the opened Fleet artifact is not a regular file or has more than one hard link, either of which could allow another directory entry to mutate the same inode concurrently. The library throws it from open_with_flags right after creating/opening the fd, guarding the Unix confined-I/O path.","triggerScenarios":"Calling open_update or open_file when the target is a directory/FIFO/device, or when a second hard link exists (st_nlink > 1) pointing at the same inode.","commonSituations":"Something hard-linked an artifact into another directory; the workspace path points at a special file; a filesystem supporting hard links (ext4, not most network FS) has a duplicate entry created by a backup or dedupe tool.","solutions":["Find and remove the extra hard link (find dir -samefile <artifact>) so nlink returns to 1","Delete and let Codewhale recreate the artifact file","Ensure the path refers to a regular file, not a directory or device node"],"exampleFix":"// before\nln existing.json artifacts/dup.json\n// after\nrm artifacts/dup.json  # keep a single link","handlingStrategy":"validation","validationCode":"use std::os::unix::fs::MetadataExt;\nlet md = std::fs::metadata(path)?;\nif !md.is_file() || md.nlink() != 1 {\n    return Err(\"artifact is not a singly-linked regular file\");\n}","typeGuard":null,"tryCatchPattern":"match open_update(dir, name) {\n    Ok(f) => edit(f),\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        eprintln!(\"artifact linked or not regular; recreate it\");\n        std::fs::remove_file(dir.join(name)).ok();\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Do not hard-link files inside the Fleet workspace","Check nlink before editing artifacts shared by backup/dedupe tools","Keep artifacts as regular files created by the tool itself"],"tags":["unix","filesystem","hardlink","integrity"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}