Schniz/fnm · error · anyhow::Error
Path is not valid UTF-8
Error message
Path is not valid UTF-8
What it means
fnm's Zsh shell integration renders `export PATH=<dir>:$PATH` from a `&Path` in `Shell::path`. `Path::to_str()` returns None when the path is not valid UTF-8, and that None becomes this anyhow error during shell-setup generation such as `fnm env --shell zsh` or `fnm use`.
Source
Thrown at src/shell/zsh.rs:18
use crate::version_file_strategy::VersionFileStrategy;
use super::shell::Shell;
use indoc::formatdoc;
use std::path::Path;
#[derive(Debug)]
pub struct Zsh;
impl Shell for Zsh {
fn to_clap_shell(&self) -> clap_complete::Shell {
clap_complete::Shell::Zsh
}
fn path(&self, path: &Path) -> anyhow::Result<String> {
let path = path
.to_str()
.ok_or_else(|| anyhow::anyhow!("Path is not valid UTF-8"))?;
let path =
super::windows_compat::maybe_fix_windows_path(path).unwrap_or_else(|| path.to_string());
Ok(format!("export PATH={path:?}:$PATH"))
}
fn set_env_var(&self, name: &str, value: &str) -> String {
format!("export {name}={value:?}")
}
fn rehash(&self) -> Option<&'static str> {
Some("rehash")
}
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let version_file_exists_condition = if config.resolve_engines() {
"-f .node-version || -f .nvmrc || -f package.json"
} else {
"-f .node-version || -f .nvmrc"View on GitHub (pinned to 86adc9676c)
Solutions
- Validate candidate vars: `for v in FNM_DIR FNM_MULTISHELL_PATH XDG_RUNTIME_DIR XDG_CACHE_HOME; do printf '%s' "${(P)v}" | iconv -f UTF-8 -t UTF-8 >/dev/null || echo "$v: invalid UTF-8"; done`.
- Set clean values: `export FNM_DIR="$HOME/.local/share/fnm"; unset FNM_MULTISHELL_PATH` and restart the shell.
- Fix LANG/LC_ALL to a UTF-8 locale so system tools generate UTF-8 names.
- Remove stale multishell symlinks in the fnm multishells storage so fresh, valid ones are created.
Example fix
# before export FNM_DIR=$'/data/b\xffnm' fnm env --shell zsh # error: Path is not valid UTF-8 # after unset FNM_DIR export FNM_DIR="$HOME/.local/share/fnm" fnm env --shell zsh # export PATH=... emitted
Defensive patterns
Strategy: validation
Validate before calling
fn fnm_paths_are_utf8() -> bool {
["FNM_DIR", "FNM_MULTISHELL_PATH", "XDG_RUNTIME_DIR", "XDG_CACHE_HOME"]
.iter()
.filter_map(std::env::var_os)
.all(|v| v.to_str().is_some())
} Type guard
fn is_utf8_path(p: &std::path::Path) -> bool {
p.to_str().is_some()
} Try / catch
match zsh_shell.path(&multishell_dir) {
Ok(line) => println!("{line}"),
Err(e) => eprintln!("fnm env failed; FNM paths must be UTF-8: {e}"),
} Prevention
- Export FNM_DIR from a UTF-8 .zshrc using a plain literal.
- Check XDG_* dirs for stray bytes after migrations or restores.
- Use `iconv` validation in bootstrap scripts before sourcing fnm env.
When it happens
Trigger: Running `fnm env --shell zsh` (or any zsh PATH rendering) when the multishell path / base dir — FNM_MULTISHELL_PATH, FNM_DIR, or the XDG runtime/cache dir it derives from — contains invalid UTF-8 bytes.
Common situations: `.zshrc` exporting FNM_DIR with non-UTF-8 bytes (file saved in a legacy encoding); XDG_RUNTIME_DIR or XDG_CACHE_HOME pointing at a byte-mangled path; macOS usernames with legacy-encoded characters; leftover multishell symlinks with invalid names.
Related errors
- Can't convert path to string
- Can't convert path to string
- Can't read PATH
- Can't convert path to string
- Can't read PATH env var
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/3b3409ed2b8e3ff8.
Report an issue: GitHub.