Hmbown/CodeWhale · error · anyhow::Error
read-only executable path is not valid UTF-8
Error message
read-only executable path is not valid UTF-8
What it means
In hardened read-only shell mode, the command is parsed to argv (hardened_readonly_argv), the program is resolved against the workspace (resolve_readonly_program), and the resulting path is converted with Path::to_str() to build a CommandSpec::program. On Unix, paths are bytes and need not be valid UTF-8; to_str() returns None for such paths, so an executable (or workspace component) containing invalid UTF-8 bytes fails here.
Source
Thrown at crates/tui/src/tools/shell.rs:2013
let policy = policy_override.unwrap_or_else(|| self.sandbox_policy.clone());
// Create command spec and prepare sandboxed environment
let spec = if let Some(workspace) = readonly_workspace {
if command.contains('|') {
// An agent read-only pipeline: every segment was admitted by
// `is_agent_readonly_shell_command` (no separators, redirects,
// expansions, or subshells — only `|` between validated
// segments), so a shell is needed solely to bind the segments
// and report a failed stage through pipefail.
let piped = format!("set -o pipefail; {command}");
CommandSpec::shell(&piped, work_dir.clone(), Duration::from_millis(timeout_ms))
} else {
let (program, args) = hardened_readonly_argv(command)?;
let program = resolve_readonly_program(&program, workspace)?;
CommandSpec::program(
program
.to_str()
.ok_or_else(|| anyhow!("read-only executable path is not valid UTF-8"))?,
args,
work_dir.clone(),
Duration::from_millis(timeout_ms),
)
}
} else {
CommandSpec::shell(command, work_dir.clone(), Duration::from_millis(timeout_ms))
};
let spec = spec.with_policy(policy).with_env(extra_env);
let exec_env = self.sandbox_manager.prepare(&spec);
if background {
let bounded_output = timeout_bounds_ms == (1, BASH_MAX_TIMEOUT_MS);
self.spawn_background_sandboxed(
command,
&work_dir,
&exec_env,
None,View on GitHub (pinned to 0c42157ee5)
Solutions
- Rename or move the executable (or the offending path component) to a valid UTF-8 name.
- Run the command outside read-only mode (plain shell mode takes a string command and does not require a UTF-8 program path).
- Fix the workspace path if a parent directory carries non-UTF-8 bytes.
Defensive patterns
Strategy: validation
Validate before calling
let program_path = resolve_program(command)?;
anyhow::ensure!(
program_path.to_str().is_some(),
"executable path {:?} is not valid UTF-8; rename it or use shell mode",
program_path
);
exec_readonly(&command)?; Try / catch
match exec_readonly(&command) {
Ok(out) => out,
Err(e) if e.to_string().contains("not valid UTF-8") => {
// Fall back to plain shell mode, which takes a string command
exec_shell(&command, None, None).await?
}
Err(e) => return Err(e),
}; Prevention
- Keep executables and workspace paths ASCII/UTF-8, especially on Unix where filenames are raw bytes.
- When targeting arbitrary user filenames, prefer the string-command shell path over hardened read-only argv mode.
When it happens
Trigger: Running a read-only-mode command whose executable lives at a path with non-UTF-8 bytes (e.g. Latin-1 or otherwise invalid byte sequences in a filename), or where the workspace root itself contains such a component.
Common situations: Filesystems with legacy non-UTF-8 filenames; files created under a different locale; almost never hit on Windows (WTF-16 paths convert) — a Unix-specific edge.
Related errors
- Persistent service has no process group id
- managed external credential access is unsupported in v0.9.1:
- shell command failed (status={}): {}
- Codewhale-owned xAI OAuth file {} is not valid UTF-8
- xAI OAuth credentials directory must be absolute
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/f02380d563e1a8ff.
Report an issue: GitHub.