espanso/espanso · error

unable to obtain dirs::data_local_dir()

Error message

unable to obtain dirs::data_local_dir()

What it means

get_legacy_runtime_dir panics with 'unable to obtain dirs::data_local_dir()' when the dirs crate cannot resolve the user's local data directory while probing for a legacy (pre-2.1) runtime directory under it. On Linux this requires $XDG_DATA_HOME or $HOME to be set and absolute; on Windows/macOS it effectively always succeeds. The legacy probe exists so espanso can migrate old runtime data, and it hard-fails when the base dir is unknown.

Source

Thrown at espanso/src/path/mod.rs:248

        if runtime_dir.is_dir() {
            return Some(runtime_dir);
        }
    }
    None
}

fn get_portable_runtime_path() -> Option<PathBuf> {
    let espanso_exe_path = std::env::current_exe().expect("unable to obtain executable path");
    let exe_dir = espanso_exe_path.parent();
    if let Some(parent) = exe_dir {
        let config_dir = parent.join(".espanso-runtime");
        return Some(config_dir);
    }
    None
}

fn get_legacy_runtime_dir() -> Option<PathBuf> {
    let data_dir = dirs::data_local_dir().expect("unable to obtain dirs::data_local_dir()");
    let espanso_dir = data_dir.join("espanso");
    if is_legacy_runtime_dir(&espanso_dir) {
        Some(espanso_dir)
    } else {
        None
    }
}

fn get_default_runtime_dir() -> Option<PathBuf> {
    let default_dir = get_default_runtime_path();
    if default_dir.is_dir() {
        Some(default_dir)
    } else {
        None
    }
}

fn get_default_runtime_path() -> PathBuf {

View on GitHub (pinned to e6c3736675)

Solutions

  1. Export HOME (and optionally XDG_DATA_HOME) as an absolute path in the execution environment before starting espanso.
  2. For systemd units, set User= plus Environment=HOME=/home/user so dirs::data_local_dir() resolves.
  3. Create a runtime dir at the default cache location (dirs::cache_dir()/espanso) or pass --runtime-dir; note the legacy probe still runs, so HOME must be valid regardless.
  4. Run espanso as the logged-in desktop user instead of via sudo/root.

Example fix

// before
$ env -i /usr/bin/espanso start   # HOME unset
unable to obtain dirs::data_local_dir()
// after
$ HOME=/home/federico XDG_DATA_HOME=/home/federico/.local/share /usr/bin/espanso start
Defensive patterns

Strategy: validation

Validate before calling

let data_local_ok = match std::env::var("XDG_DATA_HOME") {
    Ok(v) => std::path::Path::new(&v).is_absolute(),
    Err(_) => std::env::var("HOME").map(|h| std::path::Path::new(&h).is_absolute()).unwrap_or(false),
};
if !data_local_ok { eprintln!("set XDG_DATA_HOME or absolute HOME before starting espanso"); }

Type guard

fn legacy_probe_env_ok() -> bool {
    dirs::data_local_dir().is_some()
}

Try / catch

let data_dir = dirs::data_local_dir().unwrap_or_else(|| {
    eprintln!("dirs::data_local_dir() is None: set HOME/XDG_DATA_HOME");
    std::process::exit(1);
});

Prevention

When it happens

Trigger: resolve_paths -> get_runtime_dir -> get_legacy_runtime_dir on Linux with HOME unset/relative and XDG_DATA_HOME unset/relative: cron jobs, systemd units without HOME, sudo -i, containers running as a user with no HOME. Triggered on every startup where no portable/default runtime dir exists yet.

Common situations: Headless systemd services and CI containers missing HOME, misconfigured XDG_DATA_HOME pointing to a relative path, sudo dropping the environment, freshly provisioned Docker users without a home directory.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06). Data as JSON: /api/errors/1e287891136e52b5. Report an issue: GitHub.