Schniz/fnm · error · anyhow::Error

Can't convert path to string

Error message

Can't convert path to string

What it means

fnm's Bash shell integration builds an `export PATH=...` line from a `&Path` (the multishell symlink directory) in `Shell::path`. It calls `Path::to_str()`, which returns None when the path holds bytes that are not valid UTF-8, and converts that None into an anyhow error with this message. It surfaces from commands that emit shell setup, primarily `fnm env --shell bash` and `fnm use`.

Source

Thrown at src/shell/bash.rs:18

use crate::version_file_strategy::VersionFileStrategy;

use super::shell::Shell;
use indoc::formatdoc;
use std::path::Path;

#[derive(Debug)]
pub struct Bash;

impl Shell for Bash {
    fn to_clap_shell(&self) -> clap_complete::Shell {
        clap_complete::Shell::Bash
    }

    fn path(&self, path: &Path) -> anyhow::Result<String> {
        let path = path
            .to_str()
            .ok_or_else(|| anyhow::anyhow!("Can't convert path to string"))?;
        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 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"
        };
        let autoload_hook = match config.version_file_strategy() {
            VersionFileStrategy::Local => formatdoc!(
                r"

View on GitHub (pinned to 86adc9676c)

Solutions

  1. Verify the suspect env var is valid UTF-8: `printf '%s' "$FNM_DIR" | iconv -f UTF-8 -t UTF-8 >/dev/null || echo invalid` (repeat for FNM_MULTISHELL_PATH and TMPDIR).
  2. Point FNM_DIR at a clean ASCII/UTF-8 path: `export FNM_DIR="$HOME/.fnm"` and unset the broken FNM_MULTISHELL_PATH.
  3. Fix the locale (LANG/LC_ALL=en_US.UTF-8) so dependent tools stop producing non-UTF-8 names, then recreate the multishell dir by opening a new shell.
  4. If a username/home dir itself is non-UTF-8, relocate fnm storage with `--fnm-dir` to an ASCII path.

Example fix

# before
export FNM_DIR=$'/tmp/bad\xffdir'
fnm env --shell bash   # error: Can't convert path to string

# after
unset FNM_DIR
export FNM_DIR="$HOME/.local/share/fnm"
fnm env --shell bash   # export PATH=... emitted
Defensive patterns

Strategy: validation

Validate before calling

fn fnm_paths_are_utf8() -> bool {
    ["FNM_DIR", "FNM_MULTISHELL_PATH", "TMPDIR"]
        .iter()
        .filter_map(std::env::var_os)
        .all(|v| v.to_str().is_some())
}
// run before invoking `fnm env --shell bash`; abort with a clear message if false

Type guard

fn is_utf8_path(p: &std::path::Path) -> bool {
    p.to_str().is_some()
}

Try / catch

match bash_shell.path(&multishell_dir) {
    Ok(line) => println!("{line}"),
    Err(e) if e.to_string().contains("convert path to string") =>
        eprintln!("fnm dir is not valid UTF-8; check FNM_DIR / FNM_MULTISHELL_PATH"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running `fnm env --shell bash` (or any flow that renders the Bash PATH export) when the path involved — FNM_MULTISHELL_PATH, FNM_DIR, or the temp/multishell storage dir derived from them — contains invalid UTF-8 bytes.

Common situations: FNM_DIR or FNM_MULTISHELL_PATH exported from a script saved in a legacy code page; a Unix username or /tmp path with non-UTF-8 bytes (e.g. Latin-1 or Shift-JIS filenames); paths mangled by backup/restore tools; env vars set with raw bytes via `export FNM_DIR=$'\xff...'`.

Related errors


AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16). Data as JSON: /api/errors/234eff3c032c6a48. Report an issue: GitHub.