Hmbown/CodeWhale · error · io::Error
Fleet file must be a regular, non-hard-linked file
Error message
Fleet file must be a regular, non-hard-linked file
What it means
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.
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
Example fix
// before ln existing.json artifacts/dup.json // after rm artifacts/dup.json # keep a single link
Defensive patterns
Strategy: validation
Validate before calling
use std::os::unix::fs::MetadataExt;
let md = std::fs::metadata(path)?;
if !md.is_file() || md.nlink() != 1 {
return Err("artifact is not a singly-linked regular file");
} Try / catch
match open_update(dir, name) {
Ok(f) => edit(f),
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
eprintln!("artifact linked or not regular; recreate it");
std::fs::remove_file(dir.join(name)).ok();
}
Err(e) => return Err(e.into()),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Fleet file must be regular and not linked
- private sidecar file
- private sidecar file
- Automation lock must not have hard links
- Codewhale-owned credential file must be singly linked
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c86595f7df08923c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/files.rs:134
use std::os::fd::{AsRawFd, FromRawFd};
use std::os::unix::fs::MetadataExt;
// SAFETY: a pinned parent and validated basename; never follows links.
let fd = unsafe {
libc::openat(
self.directory.as_raw_fd(),
self.filename.as_ptr(),
flags | libc::O_NOFOLLOW | libc::O_CLOEXEC | libc::O_NONBLOCK,
0o600,
)
};
if fd < 0 {
return Err(io::Error::last_os_error());
}
// SAFETY: fd is freshly owned.
let file = unsafe { File::from_raw_fd(fd) };
let metadata = file.metadata()?;
if !metadata.is_file() || metadata.nlink() != 1 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Fleet file must be a regular, non-hard-linked file",
));
}
Ok(file)
}
pub(crate) fn publish(&self, bytes: &[u8]) -> io::Result<()> {
self.atomic_write(bytes, false)
}
pub(crate) fn replace(&self, bytes: &[u8]) -> io::Result<()> {
self.atomic_write(bytes, true)
}
fn atomic_write(&self, bytes: &[u8], replace: bool) -> io::Result<()> {
use std::os::fd::{AsRawFd, FromRawFd};
let temporary =View on GitHub (pinned to 73e0f67d83)