Hmbown/CodeWhale · error · InvalidData

private sidecar file

Error message

private sidecar file {} must be one regular filesystem link

What it means

On Unix, session sidecar files (locks and private reads) must be plain regular files with exactly one hard link. Metadata showing nlink != 1 means someone hard-linked or manipulated the file, which could break the private-lock protocol. The manager throws InvalidData instead of using an untrusted sidecar.

Solutions

  1. Remove the tampered sidecar file and let the session manager recreate it (usually ~/.local/share/codewhale session state)
  2. Ensure no process hard-links session state files
  3. Check for symlink/hardlink injection — this error can indicate tampering; investigate the environment
  4. If restoring from backup, restore files, not links

Example fix

// diagnose
ls -li ~/.local/share/codewhale/sessions/   # look for link count > 1
// fix
rm <sidecar-with-multiple-links>            # manager recreates it on next start
Defensive patterns

Strategy: validation

Validate before calling

let md = std::fs::metadata(&path)?;
if !md.is_file() || md.nlink() != 1 { return Err("sidecar must be a single regular file"); }

Try / catch

match manager.open_session() {
    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains("filesystem link") => recreate_sidecar(),
    other => other,
}

Prevention

When it happens

Trigger: open_private_lock_file or open_private_read_file finds the target is not a regular file (directory, FIFO, device) or has more than one hard link (nlink != 1).

Common situations: Another process hard-linking the session lock file, sidecar paths swapped with symlinks targets or pipes via tampering or misconfigured redirection, restored backups that duplicated links.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/5e41d4b4db4668ca. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/session_manager.rs:191

    }
    #[cfg(windows)]
    {
        use std::os::windows::fs::OpenOptionsExt as _;
        use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_OPEN_REPARSE_POINT;
        options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT);
    }
    let file = options.open(path)?;
    validate_private_regular_file(&file, path)?;
    Ok(file)
}

#[cfg(unix)]
fn validate_private_regular_file(file: &fs::File, path: &Path) -> io::Result<()> {
    use std::os::unix::fs::MetadataExt as _;

    let metadata = file.metadata()?;
    if !metadata.is_file() || metadata.nlink() != 1 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "private sidecar file {} must be one regular filesystem link",
                path.display()
            ),
        ));
    }
    Ok(())
}

#[cfg(windows)]
fn validate_private_regular_file(file: &fs::File, path: &Path) -> io::Result<()> {
    use std::os::windows::fs::MetadataExt as _;
    use std::os::windows::io::AsRawHandle as _;
    use windows_sys::Win32::Storage::FileSystem::{
        BY_HANDLE_FILE_INFORMATION, FILE_ATTRIBUTE_REPARSE_POINT, GetFileInformationByHandle,
    };

View on GitHub (pinned to 433685b202)