Hmbown/CodeWhale · error
could not inspect workspace .env link count
Error message
could not inspect workspace .env link count: {error} What it means
On Windows, hard-link/symlink detection for the workspace `.env` uses `GetFileInformationByHandle` to read `nNumberOfLinks`. If the Win32 call fails, the error is wrapped with this message, because the loader must prove the file is unique before trusting its contents.
Solutions
- Move the workspace `.env` onto a local NTFS volume.
- Check the `{error}` suffix (Win32 error code) for the failing subsystem (AV, permissions, filesystem).
- Ensure the file is a normal regular file, not on a UNC/network share, then retry startup.
Defensive patterns
Strategy: fallback
Try / catch
match load_workspace_dotenv_credentials_from_path(&path) {
Err(e) if e.to_string().contains("link count") => {
eprintln!("move .env to local NTFS storage: {e:#}");
}
other => other?,
} Prevention
- On Windows, keep `.env` on local NTFS, not UNC/network shares or WSL mounts.
- Exclude the workspace from AV handle-inspection interference if it recurs.
- Never hard-link or symlink the workspace `.env`.
When it happens
Trigger: The `GetFileInformationByHandle` syscall fails (invalid handle, AV interference, filesystem without link metadata) inside `workspace_dotenv_has_multiple_links` on Windows.
Common situations: The `.env` lives on an unusual filesystem (network drive, WSL mount) where the handle query fails, or security software blocks handle inspection.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Automation lock must not be a reparse point
- Codewhale-owned credential file must be singly linked
- config lock was redirected while opening
- could not securely open
- external credential path must name a non-reparse regular…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d0c4102222c2e28d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:3000
#[cfg(windows)]
fn workspace_dotenv_has_multiple_links(
file: &std::fs::File,
_metadata: &std::fs::Metadata,
) -> Result<bool> {
use std::os::windows::io::AsRawHandle;
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Storage::FileSystem::{
BY_HANDLE_FILE_INFORMATION, GetFileInformationByHandle,
};
let mut information = BY_HANDLE_FILE_INFORMATION::default();
// SAFETY: `file` owns a live kernel handle for the already-open `.env`;
// `information` remains writable for the duration of this synchronous
// call. No path lookup or re-open occurs here.
unsafe {
GetFileInformationByHandle(HANDLE(file.as_raw_handle()), &mut information)
.map_err(|error| anyhow!("could not inspect workspace .env link count: {error}"))?;
}
Ok(information.nNumberOfLinks > 1)
}
#[cfg(not(any(unix, windows)))]
fn workspace_dotenv_has_multiple_links(
_file: &std::fs::File,
_metadata: &std::fs::Metadata,
) -> Result<bool> {
Ok(false)
}
#[cfg(unix)]
fn open_workspace_dotenv_without_following_links(path: &Path) -> Result<std::fs::File> {
use std::os::unix::fs::OpenOptionsExt;
std::fs::OpenOptions::new()
.read(true)View on GitHub (pinned to 73e0f67d83)