Hmbown/CodeWhale · error · anyhow::Error
{} is a symbolic link, not a workspace-owned file
Error message
{} is a symbolic link, not a workspace-owned file What it means
Fallback implementation of the no-symlink contract for platforms that are neither unix nor windows: open_workspace_dotenv_without_following_links stats .env with symlink_metadata (lstat semantics) and refuses the load if the entry itself is a symbolic link, then opens the file normally. Same ownership rule as the unix/windows paths, expressed portably.
Source
Thrown at crates/tui/src/lib.rs:2734
.map_err(|error| anyhow!("could not securely open {}: {error}", path.display()))?;
let metadata = file
.metadata()
.map_err(|error| anyhow!("could not inspect {}: {error}", path.display()))?;
if metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
bail!(
"{} is a reparse point, not a workspace-owned file",
path.display()
);
}
Ok(file)
}
#[cfg(not(any(unix, windows)))]
fn open_workspace_dotenv_without_following_links(path: &Path) -> Result<std::fs::File> {
let metadata = std::fs::symlink_metadata(path)
.map_err(|error| anyhow!("could not inspect {}: {error}", path.display()))?;
if metadata.file_type().is_symlink() {
bail!(
"{} is a symbolic link, not a workspace-owned file",
path.display()
);
}
std::fs::File::open(path)
.map_err(|error| anyhow!("could not securely open {}: {error}", path.display()))
}
/// Generate shell completions for the given shell
fn generate_completions(shell: Shell) {
let mut cmd = Cli::command();
let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut io::stdout());
}
/// Run the offline evaluation harness (no network/LLM calls).
fn run_eval(args: EvalArgs) -> Result<()> {
let fail_step = match args.fail_step.as_deref() {View on GitHub (pinned to 0c42157ee5)
Solutions
- Replace the symlink with a real file containing the literal values
- Keep per-workspace literal .env files instead of symlinking a shared one
Example fix
# before ls -l .env # .env -> /shared/secrets.env # after cp -L /shared/secrets.env .env # real file, literal values
Defensive patterns
Strategy: validation
Validate before calling
# Portable pre-check: entry must not itself be a symlink
[ ! -L .env ] || { echo '.env is a symbolic link; replace with a real file'; exit 2; } Type guard
fn env_not_symlink(path: &Path) -> bool {
!std::fs::symlink_metadata(path)
.map(|m| m.file_type().is_symlink())
.unwrap_or(true)
} Prevention
- Copy secrets into a per-workshop literal .env instead of symlinking
- Verify with ls -l that .env is not an arrow (`->`) entry
When it happens
Trigger: Running on a non-unix, non-windows target (for example wasi or another tier-3 platform) where the workspace .env is a symbolic link to another file.
Common situations: Exotic embedder/test targets; workspace setups that symlink dotfiles from a central store, ported to unusual platforms.
Related errors
- config path must not be a symlink: {}
- {} is not a regular file
- {} has multiple filesystem links, not a unique workspace-own
- MCP config path must be a regular file: {}
- refusing non-regular or reparse-point config lock at {}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/81474622bd904914.
Report an issue: GitHub.