Hmbown/CodeWhale · error · InvalidData

private sidecar file

Error message

private sidecar file {} must have exactly one filesystem link

What it means

On Windows, after checking file type and reparse attributes, validate_private_regular_file also requires nNumberOfLinks == 1 via GetFileInformationByHandle. Multiple hard links mean the sidecar is shared, breaking the private-file guarantee, so the manager throws InvalidData.

Solutions

  1. Delete the extra hard links (or the sidecar itself; the manager recreates it)
  2. Check with fsutil hardlink list <file> where the other links live
  3. Stop tools that hard-link session state (backup dedup, link shells extension)

Example fix

// diagnose
fsutil hardlink list <sidecar-path>
// fix
rm <sidecar-path>            # recreate clean sidecar
Copy-Item <source> <dest>    # use copies, not hard links, for state sharing
Defensive patterns

Strategy: validation

Validate before calling

// Windows: check hard-link count before opening
let links = std::fs::metadata(&path)?.file_attributes(); // full check needs GetFileInformationByHandle; pre-check existence + regular

Try / catch

match manager.open_session() {
    Err(e) if e.to_string().contains("exactly one filesystem link") => recreate_sidecar(),
    other => other,
}

Prevention

When it happens

Trigger: open_private_lock_file / open_private_read_file succeeds in opening the file, but BY_HANDLE_FILE_INFORMATION reports nNumberOfLinks != 1 (file hard-linked elsewhere).

Common situations: Hard-linking the lock file via mklink /H or backup tools that create hard links; sharing a profile directory via hard links instead of copies.

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/d79222601977d474. Report an issue: GitHub.

Appendix: source

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

    };

    let metadata = file.metadata()?;
    if !metadata.is_file() || metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "private sidecar file {} must be a non-reparse regular file",
                path.display()
            ),
        ));
    }
    let mut info = BY_HANDLE_FILE_INFORMATION::default();
    // SAFETY: `file` keeps the handle valid and `info` is writable for the call.
    if unsafe { GetFileInformationByHandle(file.as_raw_handle(), &mut info) } == 0 {
        return Err(io::Error::last_os_error());
    }
    if info.nNumberOfLinks != 1 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "private sidecar file {} must have exactly one filesystem link",
                path.display()
            ),
        ));
    }
    Ok(())
}

#[cfg(all(not(unix), not(windows)))]
fn validate_private_regular_file(file: &fs::File, path: &Path) -> io::Result<()> {
    if !file.metadata()?.is_file() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("private sidecar file {} must be regular", path.display()),
        ));
    }

View on GitHub (pinned to 433685b202)