Hmbown/CodeWhale · error · io::Error

Fleet file must be regular and not linked

Error message

Fleet file must be regular and not linked

What it means

This error means the Fleet artifact opened for update on Windows (or via the metadata check path) is not a regular file, appears to be a link/reparse point per its metadata, or has a link count other than 1. The library throws it from open_update to keep confined artifact I/O on plain, singly-linked regular files.

Solutions

  1. Remove the extra hard link or replace the symlink with a real file, then retry
  2. Delete the artifact and let Codewhale recreate it as a fresh regular file
  3. Verify with fsutil hardlink list <artifact> that only one link exists

Example fix

// before
mklink artifact.json real.json  # symlink
// after
copy real.json artifact.json  # regular file, single link
Defensive patterns

Strategy: validation

Validate before calling

let md = std::fs::symlink_metadata(path)?;
if !md.is_file() {
    return Err("artifact is not a regular file (symlink/junction or special file)");
}
// on Windows verify link count via GetFileInformationByHandle before updating

Try / catch

match open_update(ws) {
    Ok(f) => edit(f),
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
        eprintln!("artifact is a link or multi-linked; recreate it");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling open_update when the file is a symlink/junction (metadata_is_link_or_reparse true), a non-regular file type, or windows_file_identity reports links != 1 (a hard link exists).

Common situations: An NTFS hard link was created to the artifact; the artifact path was replaced by a symlink; the artifact is a directory or device; a dedupe/backup tool created alternate links.

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


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/abace10effde00b0. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/fleet/files.rs:302

    }

    pub(crate) fn open_update(&self, create: bool, append: bool) -> io::Result<File> {
        use std::os::windows::fs::OpenOptionsExt;
        let file = std::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .append(append)
            .create(create)
            .truncate(false)
            .share_mode(0x0000_0007)
            .custom_flags(0x0020_0000)
            .open(self.directory.join(&self.filename))?;
        let metadata = file.metadata()?;
        if !metadata.is_file()
            || crate::plugins::metadata_is_link_or_reparse(&metadata)
            || crate::plugins::windows_file_identity(&file)?.links != 1
        {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Fleet file must be regular and not linked",
            ));
        }
        Ok(file)
    }

    pub(crate) fn open_file(&self) -> io::Result<File> {
        // Existing protected reader rejects reparse points, hard links and
        // non-regular files, and denies concurrent writes/replacement.
        crate::plugins::manifest::open_bundle_file(&self.directory.join(&self.filename))
    }

    pub(crate) fn publish(&self, bytes: &[u8]) -> io::Result<()> {
        self.atomic_write(bytes, false)
    }

    pub(crate) fn replace(&self, bytes: &[u8]) -> io::Result<()> {

View on GitHub (pinned to 73e0f67d83)