Schniz/fnm · error · anyhow::Error

Can't read PATH env var

Error message

Can't read PATH env var

What it means

PowerShell's `Shell::path` reads the current process PATH with `std::env::var_os("PATH")` so it can prepend fnm's bin dir and re-emit `$env:PATH = ...`. If no PATH variable exists in the environment at all, `var_os` returns None and this anyhow error is produced while running `fnm env --shell power-shell` or `fnm use`.

Source

Thrown at src/shell/powershell.rs:13

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(&current_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 {

View on GitHub (pinned to 86adc9676c)

Solutions

  1. Restore a PATH before invoking fnm: PowerShell `$env:PATH = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [Environment]::GetEnvironmentVariable('Path','User')`.
  2. In containers/cron, export a baseline: `PATH=/usr/local/bin:/usr/bin:/bin` (Windows: `set PATH=C:\Windows\System32;C:\Windows`).
  3. If spawning fnm from code, replace `env_clear()` with selective env removal or re-pass PATH explicitly.
  4. Update fnm; newer releases may degrade gracefully by emitting only fnm's bin dir.

Example fix

# before (PowerShell, PATH was removed)
Remove-Item Env:PATH
fnm env --shell power-shell   # error: Can't read PATH env var

# after
$env:PATH = [Environment]::GetEnvironmentVariable('Path','Machine')
fnm env --shell power-shell   # $env:PATH = ... emitted
Defensive patterns

Strategy: validation

Validate before calling

// PowerShell: fail fast before calling fnm
if (-not $env:PATH) { throw "PATH is not set; refusing to run fnm env" }
fnm env --shell power-shell

Type guard

fn has_path_env() -> bool {
    std::env::var_os("PATH").is_some()
}

Try / catch

$out = fnm env --shell power-shell 2>&1
if ($LASTEXITCODE -ne 0 -and "$out" -match "Can't read PATH env var") {
    $env:PATH = [Environment]::GetEnvironmentVariable('Path','Machine')
    $out = fnm env --shell power-shell
}

Prevention

When it happens

Trigger: `fnm env --shell power-shell` / `fnm use` in a process whose environment has no PATH — spawned via `env -i`, `Command::env_clear()` without re-adding PATH, a stripped CI/cron/scheduled-task environment, or a minimal container.

Common situations: Minimal Docker images invoked with a sanitized env; Windows scheduled tasks or services with no user environment; CI steps that `Remove-Item Env:PATH` or start powershell with `-Command` from a bare service; test harnesses that clear the environment.

Related errors


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