Hmbown/CodeWhale · error
no trusted executable search path remains outside the…
Error message
no trusted executable search path remains outside the workspace
What it means
After rejecting path-qualified programs, the resolver filters the process PATH down to entries that are absolute and canonicalize outside the workspace (`readonly_sanitized_path_from`). If no PATH entry survives — every entry is relative, unresolvable, or inside the workspace — this error is thrown because no trusted location exists to resolve the allowlisted executable from.
Solutions
- Add a system-wide directory outside the workspace to PATH, e.g. `PATH=/usr/local/bin:/usr/bin:$PATH`
- Move the required binary to an installed location (`cargo install`, distro package, /usr/local/bin)
- Ensure PATH entries are absolute and point at existing directories outside the workspace
Example fix
// before PATH=./node_modules/.bin app // after PATH=/usr/local/bin:/usr/bin app # tool installed system-wide
Defensive patterns
Strategy: validation
Validate before calling
fn has_trusted_path_entries(workspace: &std::path::Path) -> bool {
let Some(path) = std::env::var_os("PATH") else { return false };
let Ok(workspace) = workspace.canonicalize() else { return false };
std::env::split_paths(&path).any(|entry| {
entry.is_absolute()
&& entry.canonicalize().map(|r| !r.starts_with(&workspace)).unwrap_or(false)
})
}
assert!(has_trusted_path_entries(&workspace), "PATH needs an absolute entry outside the workspace"); Prevention
- Keep at least one absolute system directory (/usr/bin, /usr/local/bin) on PATH
- Do not prepend only workspace-relative or vendored directories to PATH
- Remove dangling symlinks/dead directories from PATH; verify with `which -a <tool>` resolving outside the workspace
When it happens
Trigger: Running with `PATH=.` or `PATH=$HOME/project` (the workspace itself); PATH containing only relative entries like `bin`; running with cwd-inside-workspace PATH entries so the filter removes them all; PATH entries that are dangling symlinks or nonexistent directories that fail canonicalize().
Common situations: Vendored-tool setups that prepend the project's `node_modules/.bin` or `target/debug` to PATH as the only entry; sandboxes that rewrite PATH to workspace-relative dirs; broken images where PATH points at removed directories.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- no executable search path is configured
- allowlisted read-only executable
- classifier-approved Git read did not keep its subcommand in…
- classifier-approved Git read was missing its literal…
- Codewhale credentials directory has an unsupported component
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1f453ff41934b3d0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/shell.rs:4396
fn resolve_readonly_program(program: &str, workspace: &std::path::Path) -> Result<PathBuf> {
let path = std::env::var_os("PATH")
.ok_or_else(|| anyhow!("no executable search path is configured"))?;
resolve_readonly_program_from_path(program, workspace, &path)
}
fn resolve_readonly_program_from_path(
program: &str,
workspace: &std::path::Path,
path: &std::ffi::OsStr,
) -> Result<PathBuf> {
let workspace = workspace.canonicalize()?;
if std::path::Path::new(program).components().count() != 1 {
return Err(anyhow!(
"read-only command must name a bare allowlisted executable"
));
}
let safe_path = readonly_sanitized_path_from(&workspace, path).ok_or_else(|| {
anyhow!("no trusted executable search path remains outside the workspace")
})?;
let names = if cfg!(windows) {
vec![format!("{program}.exe"), format!("{program}.com")]
} else {
vec![program.to_string()]
};
for directory in std::env::split_paths(&safe_path) {
for name in &names {
let candidate = directory.join(name);
if !candidate.is_file() {
continue;
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;
if candidate.metadata()?.permissions().mode() & 0o111 == 0 {
continue;
}View on GitHub (pinned to 73e0f67d83)