Schniz/fnm · critical
choosing base strategy
Error message
choosing base strategy
What it means
`Directories::default()` builds fnm's whole directory layout by calling `etcetera::choose_base_strategy()`, which must resolve the user's home directory (HOME on Unix, USERPROFILE on Windows). If that resolution fails, the Result is unwrapped with `.expect("choosing base strategy")`, so every fnm command panics immediately at startup before any argument handling.
Source
Thrown at src/directories.rs:38
fn state_dir(basedirs: &impl BaseStrategy) -> Option<PathBuf> {
xdg_dir("XDG_STATE_HOME").or_else(|| basedirs.state_dir())
}
fn cache_dir(basedirs: &impl BaseStrategy) -> PathBuf {
xdg_dir("XDG_CACHE_HOME").unwrap_or_else(|| basedirs.cache_dir())
}
/// A helper struct for directories in fnm that uses XDG Base Directory Specification
/// if applicable for the platform.
#[derive(Debug, Clone)]
pub struct Directories(
#[cfg(windows)] etcetera::base_strategy::Windows,
#[cfg(not(windows))] etcetera::base_strategy::Xdg,
);
impl Default for Directories {
fn default() -> Self {
Self(etcetera::choose_base_strategy().expect("choosing base strategy"))
}
}
impl Directories {
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;View on GitHub (pinned to 86adc9676c)
Solutions
- Export a home explicitly: `export HOME=/root` (or for the service user) before invoking fnm.
- For systemd units add `Environment=HOME=/var/lib/myuser`; for cron add `HOME=/root` at the top of the crontab.
- In Dockerfiles set `ENV HOME=/root` (or create the user with a home via `useradd -m`).
- If patching fnm: replace the expect with graceful error propagation or fall back to the current directory/stdout-only mode.
Example fix
# before env -i /usr/local/bin/fnm list # panic: choosing base strategy # after env -i HOME=/tmp/fnm-home /usr/local/bin/fnm list # works (creates dirs under HOME)
Defensive patterns
Strategy: validation
Validate before calling
fn home_env_present() -> bool {
let key = if cfg!(windows) { "USERPROFILE" } else { "HOME" };
std::env::var_os(key).is_some()
}
// run before any fnm invocation; otherwise export HOME=/tmp/fnm-home Try / catch
std::panic::catch_unwind(|| run_fnm(args))
.unwrap_or_else(|_| {
eprintln!("fnm crashed at startup: HOME/USERPROFILE is probably unset");
std::process::exit(78); // EX_CONFIG
}); Prevention
- Always set HOME (Unix) / USERPROFILE (Windows) in cron, systemd units, and containers.
- In Dockerfiles, prefer `USER` with a created home (`useradd -m`).
- Smoke-test `fnm --version` in the target environment during provisioning.
When it happens
Trigger: Running any fnm command (`fnm list`, `fnm env`, ...) in a process where HOME/USERPROFILE is unset and the OS-level lookup also fails — `env -i fnm list`, a systemd unit/cron entry without `Environment=HOME=...`, a service account whose passwd entry has no usable home, or a minimal container.
Common situations: Docker images run with a scrubbed env; cron jobs and systemd timers (which start with a sparse environment); `sudo` into service users with env_reset; hardened CI runners that strip HOME; chroot/build sandboxes.
Related errors
- Can't get home directory
- Can't read PATH env var
- Can't read PATH env var
- Can't get a temporary file
- Failed to grab exit code
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/94e83da49e405c13.
Report an issue: GitHub.