Schniz/fnm · error

Can't get home directory

Error message

Can't get home directory

What it means

On macOS only, when neither the modern data dir (`~/Library/Application Support/fnm`) nor the legacy `~/.fnm` exists yet, `Directories::default_base_dir` constructs an etcetera `Apple` base strategy — which resolves the home directory — and unwraps it with `.expect("Can't get home directory")`. If the home directory cannot be determined at that moment, fnm panics while computing where to put its files.

Source

Thrown at src/directories.rs:61

    pub fn strategy(&self) -> &impl BaseStrategy {
        &self.0
    }

    pub fn default_base_dir(&self) -> PathBuf {
        let strategy = self.strategy();
        let modern = strategy.data_dir().join("fnm");
        if modern.exists() {
            return modern;
        }

        let legacy = strategy.home_dir().join(".fnm");
        if legacy.exists() {
            return legacy;
        }

        #[cfg(target_os = "macos")]
        {
            let basedirs = etcetera::base_strategy::Apple::new().expect("Can't get home directory");
            let legacy = basedirs.data_dir().join("fnm");
            if legacy.exists() {
                return legacy;
            }
        }

        modern.ensure_exists_silently()
    }

    pub fn multishell_storage(&self) -> PathBuf {
        let basedirs = self.strategy();
        let dir = runtime_dir(basedirs)
            .or_else(|| state_dir(basedirs))
            .unwrap_or_else(|| cache_dir(basedirs));
        dir.join("fnm_multishells")
    }
}

View on GitHub (pinned to 86adc9676c)

Solutions

  1. Ensure HOME is set and writable: `export HOME="$HOME"` sanity check, or set it explicitly in the launching plist/agent (`EnvironmentVariables` → HOME).
  2. Pre-create either `~/.fnm` or `~/Library/Application Support/fnm` so the earlier existence checks return before the Apple fallback runs.
  3. For daemons/agents, run fnm once from a normal login shell first to materialize the directories.
  4. Update fnm — this fallback should degrade to a user-facing error rather than a panic.

Example fix

# before
env -i fnm list   # macOS first run, panic: Can't get home directory

# after
mkdir -p "$HOME/Library/Application Support/fnm"
env -i HOME="$HOME" fnm list   # ok
Defensive patterns

Strategy: validation

Validate before calling

# macOS: ensure fnm dirs exist before first run in stripped environments
mkdir -p "$HOME/Library/Application Support/fnm" || exit 1
[ -n "$HOME" ] || { echo 'HOME unset; aborting' >&2; exit 1; }

Try / catch

std::panic::catch_unwind(|| run_fnm(args))
    .unwrap_or_else(|_| {
        eprintln!("fnm could not resolve the home directory; set HOME and retry");
        std::process::exit(1);
    });

Prevention

When it happens

Trigger: First run of any fnm command on macOS (no ~/.fnm, no Application Support/fnm) in an environment where HOME is unset or unresolvable — `env -i fnm list`, launchd agents with a stripped environment, or ssh contexts with unusual passwd entries.

Common situations: macOS LaunchAgents/LaunchDaemons that omit HOME; CI runners on macOS with minimal env; scripts run via `env -i`; first-ever invocation right after install in a sanitized shell.

Related errors


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