Schniz/fnm · error · anyhow::Error
Can't read PATH
Error message
Can't read PATH
What it means
Once the new PATH is joined, PowerShell's `Shell::path` must render it inside a plain-string snippet (`$env:PATH = "..."`), so the joined OsString is converted with `to_str()`. If any pre-existing PATH entry holds bytes that are not valid UTF-8, the conversion returns None and this anyhow error fires.
Source
Thrown at src/shell/powershell.rs:20
use super::Shell;
use indoc::formatdoc;
use std::path::Path;
#[derive(Debug)]
pub struct PowerShell;
impl Shell for PowerShell {
fn path(&self, path: &Path) -> anyhow::Result<String> {
let current_path =
std::env::var_os("PATH").ok_or_else(|| anyhow::anyhow!("Can't read PATH env var"))?;
let mut split_paths: Vec<_> = std::env::split_paths(¤t_path).collect();
split_paths.insert(0, path.to_path_buf());
let new_path = std::env::join_paths(split_paths)
.map_err(|source| anyhow::anyhow!("Can't join paths: {source}"))?;
let new_path = new_path
.to_str()
.ok_or_else(|| anyhow::anyhow!("Can't read PATH"))?;
Ok(self.set_env_var("PATH", new_path))
}
fn set_env_var(&self, name: &str, value: &str) -> String {
format!(r#"$env:{name} = "{value}""#)
}
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let version_file_exists_condition = if config.resolve_engines() {
"(Test-Path .nvmrc) -Or (Test-Path .node-version) -Or (Test-Path package.json)"
} else {
"(Test-Path .nvmrc) -Or (Test-Path .node-version)"
};
let autoload_hook = match config.version_file_strategy() {
VersionFileStrategy::Local => formatdoc!(
r"
If ({version_file_exists_condition}) {{ & fnm use --silent-if-unchanged }}
",View on GitHub (pinned to 86adc9676c)
Solutions
- Identify suspicious entries: iterate `($env:PATH -split ';')` and look for garbled/replacement characters.
- Remove or rename the offending entry (rename the folder to ASCII, or drop it from PATH via system settings).
- Re-set PATH from a known-good value: `[Environment]::SetEnvironmentVariable('Path', $clean, 'User')`.
- Ensure system locale / 'Beta: Use Unicode UTF-8 for worldwide language support' is consistent with how folders were named.
Example fix
# before $env:PATH = "C:\Users\<garbled-ansi-name>\bin;" + $env:PATH fnm env --shell power-shell # error: Can't read PATH # after $env:PATH = "C:\Users\me\bin;" + $env:PATH fnm env --shell power-shell # ok
Defensive patterns
Strategy: validation
Validate before calling
fn path_entries_are_utf8() -> bool {
std::env::var_os("PATH")
.map(|p| std::env::split_paths(&p).all(|e| e.as_os_str().to_str().is_some()))
.unwrap_or(false)
} Type guard
fn is_utf8_os_string(s: &std::ffi::OsStr) -> bool {
s.to_str().is_some()
} Try / catch
if !path_entries_are_utf8() {
eprintln!("PATH contains non-UTF-8 entries; fix them before running fnm env");
std::process::exit(1);
} Prevention
- Keep PATH entries ASCII or proper UTF-8; rename legacy-encoded folders.
- Use the Windows UTF-8 system locale when creating directories that will appear in PATH.
- Set PATH from a verified script rather than accumulating entries from old installers.
When it happens
Trigger: `fnm env --shell power-shell` when at least one existing PATH entry is non-UTF-8 — e.g. a directory created under an ANSI code page (Shift-JIS, Latin-1) on Windows, or a raw-byte path on Unix — so the joined string cannot be expressed as Rust `&str`.
Common situations: Non-English Windows profiles with legacy-encoded folder names in PATH (e.g. `C:\Users\< Shift-JIS name >\bin`); mojibake entries pasted from webpages; WSL paths with invalid bytes; PATH edited via tooling that wrote the registry value in the wrong encoding.
Related errors
- Can't convert path to string
- Can't convert path to string
- Can't convert path to string
- Can't read PATH env var
- Can't join paths: {source}
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/39286eae9635a0ef.
Report an issue: GitHub.