Schniz/fnm · error · anyhow::Error
Can't join paths: {source}
Error message
Can't join paths: {source} What it means
After splitting the existing PATH and inserting fnm's bin dir at the front, `Shell::path` for PowerShell rebuilds one PATH string with `std::env::join_paths`. That function fails when any single entry contains the platform's path separator character itself (`;` on Windows, `:` on Unix), because the separator cannot appear unescaped inside an element. The io::Error is wrapped into this anyhow error.
Source
Thrown at src/shell/powershell.rs:17
use crate::version_file_strategy::VersionFileStrategy;
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!(View on GitHub (pinned to 86adc9676c)
Solutions
- Locate the offending entry: `($env:PATH -split ';') | Where-Object { $_ -match '\\|/' -and (Test-Path $_) -eq $false }` — inspect entries that look like two paths glued by `;`.
- Rebuild a clean PATH excluding the malformed element, or rename the folder so it has no `;`.
- On Unix check for `:` inside PATH entries: `echo "$PATH" | tr ':' '\n' | grep ':'` (anything surviving the split embeds a colon).
- Re-run `fnm env --shell power-shell` after fixing PATH.
Example fix
# before $env:PATH = 'C:\tools\a;b'; + $env:PATH # one entry containing ';' fnm env --shell power-shell # error: Can't join paths # after $env:PATH = 'C:\tools\a;C:\tools\b' + ';' + $env:PATH fnm env --shell power-shell # ok
Defensive patterns
Strategy: validation
Validate before calling
fn path_is_joinable() -> bool {
let sep = if cfg!(windows) { ';' } else { ':' };
std::env::var_os("PATH")
.map(|p| {
std::env::split_paths(&p)
.all(|entry| !entry.as_os_str().to_string_lossy().contains(sep))
})
.unwrap_or(false)
} Try / catch
match powershell.path(&dir) {
Ok(out) => out,
Err(e) if e.to_string().contains("join paths") =>
panic!("a PATH entry embeds the path separator; clean $env:PATH first: {e}"),
Err(e) => return Err(e),
} Prevention
- Quote every PATH entry you append that may contain ';'.
- Prefer two well-separated entries over one entry with an internal separator.
- Audit PATH after running third-party installers.
When it happens
Trigger: `fnm env --shell power-shell` when the current PATH contains one malformed entry embedding `;` inside a directory name (e.g. `C:\tools\a;b` set without quoting), or on Unix an entry containing `:`.
Common situations: Windows installers appending unquoted paths with semicolons in folder names; hand-edited system PATH in the registry dropping quotes; WSL interop appending Windows paths into $PATH; scripts doing `$env:PATH += 'C:\a;b'`.
Related errors
- Can't join paths: {err}
- Can't read PATH
- Can't read PATH env var
- Can't read PATH env var
- Can't convert path to string
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/d5eb8f3c375c3025.
Report an issue: GitHub.