Hmbown/CodeWhale · error
private sidecar file
Error message
private sidecar file {path} must have exactly one filesystem link What it means
On Windows, after confirming the sidecar is a regular non-reparse file, session_manager checks via GetFileInformationByHandle that nNumberOfLinks is exactly 1. More than one link means the file is hard-linked elsewhere, so another path could observe or tamper with the private file; such files are rejected as InvalidData.
Solutions
- Find the extra links (e.g. `fsutil hardlink list <path>`) and delete them, leaving one link.
- Restore the file from a copy that is not hardlinked.
- Disable hardlink-based dedupe/backup for the sessions directory.
Example fix
// before: file duplicated via hardlink by backup tool fsutil hardlink list session.lock // shows 2 links // after: keep one link copy session.lock session.lock.new && move /y session.lock.new session.lock
Defensive patterns
Strategy: validation
Validate before calling
// Windows: reject hardlinked files before opening
fn has_single_link(p: &Path) -> bool {
std::fs::metadata(p).map(|m| m.number_of_links() == Some(1)).unwrap_or(false)
} Try / catch
match open_private_read_file(path) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => eprintln!("hardlink detected, restore a single-link copy"),
other => other?,
} Prevention
- Disable hardlink dedupe in backup tools for the sessions dir.
- Restore session state from real copies, not hardlinked trees.
- Periodically run `fsutil hardlink list` on session files if backups run locally.
When it happens
Trigger: Calling open_private_lock_file or open_private_read_file on Windows when the sidecar file has 2+ hard links (nNumberOfLinks != 1).
Common situations: A hardlink-creating backup tool (e.g. rsync-like dedupe, Time-Machine-style snapshots on NTFS) linked the session file; the user hardlinked files manually; a restore tool reconstructed the tree with hardlinks.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Codewhale-owned credential file must be singly linked
- Fleet file must be regular and not linked
- private sidecar file
- Automation lock must not be a reparse point
- Codewhale-owned xAI OAuth path has the wrong filesystem type
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/f46fadc474e41a2d.
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 73e0f67d83)