a-b-street/abstreet · error

This build of A/B Street stores player data in…

Error message

This build of A/B Street stores player data in $HOME/.abstreet, but $HOME isn't set: {}

What it means

When a release build is compiled with ABST_PLAYER_HOME_DIR set, abstio::path resolves 'player/...' paths under $HOME/.abstreet. At first use (lazily, inside OnceLock::get_or_init) it reads the HOME environment variable; if HOME is unset or invalid it panics with this message. The library assumes a POSIX-style HOME is present for such packaged builds.

Solutions

  1. Set the HOME environment variable before launching the binary (e.g. export HOME=/home/user, or in systemd use Environment=HOME=/var/lib/abstreet, in Docker use ENV HOME=... or -e HOME=...)
  2. Rebuild without ABST_PLAYER_HOME_DIR so the library falls back to the data/-relative player dir instead of $HOME/.abstreet
  3. Modify the code to fall back to std::env::var_os or dirs::home_dir()/std::env::temp_dir() instead of panicking when HOME is missing
  4. Run the program as a user whose home directory exists and whose environment includes HOME (e.g. via su/login shell rather than a bare service exec)

Example fix

// before (shell)
./abstreet  # built with ABST_PLAYER_HOME_DIR=1, panics: HOME isn't set
// after (shell)
export HOME="$HOME"; ./abstreet
# or rebuild:
unset ABST_PLAYER_HOME_DIR && cargo build --release
Defensive patterns

Strategy: validation

Validate before calling

if std::env::var_os("HOME").map(|h| !h.is_empty()).unwrap_or(false) {
    // safe to call abstio::path("player/...") in an ABST_PLAYER_HOME_DIR build
} else {
    eprintln!("HOME must be set for player data");
}

Type guard

fn home_is_set() -> bool {
    std::env::var_os("HOME").map(|h| !h.is_empty()).unwrap_or(false)
}

Try / catch

// Rust panics are not catchable via Result; wrap startup in catch_unwind if you must recover
let ok = std::panic::catch_unwind(|| abstio::path("player/settings.json"));
match ok {
    Ok(p) => println!("player dir ok: {}", p),
    Err(_) => eprintln!("HOME not set; cannot use player data"),
}

Prevention

When it happens

Trigger: Calling abstio::path (directly or via path_player, path_edits, path_save, path_camera_state, path_trips, path_ltn_proposals) with a path starting with 'player/' in a binary compiled with ABST_PLAYER_HOME_DIR=1 (option_env!) while the HOME env var is unset (Err from std::env::var, e.g. NotUnicode or NotPresent). Note the value is baked in at compile time, so any release binary built with that flag will demand HOME at runtime.

Common situations: Packaged release builds (or distro/CI builds that set ABST_PLAYER_HOME_DIR) run under environments with no HOME: systemd services, cron, Docker containers running as non-root or with HOME cleared, macOS launchd, or Windows builds where HOME is not defined.

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 a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/423febaf79d67d50. Report an issue: GitHub.

Appendix: source

Thrown at abstio/src/abst_paths.rs:28

use serde::{Deserialize, Serialize};

use abstutil::basename;

use crate::{file_exists, list_all_objects, Manifest};

static ROOT_DIR: OnceLock<String> = OnceLock::new();
static ROOT_PLAYER_DIR: OnceLock<String> = OnceLock::new();

pub fn path<I: AsRef<str>>(p: I) -> String {
    let p = p.as_ref();
    if p.starts_with("player/") {
        let dir = ROOT_PLAYER_DIR.get_or_init(|| {
            // If you're packaging for a release and want the player's local data directory to be
            // $HOME/.abstreet, set ABST_PLAYER_HOME_DIR=1
            if option_env!("ABST_PLAYER_HOME_DIR").is_some() {
                match std::env::var("HOME") {
                    Ok(dir) => format!("{}/.abstreet", dir.trim_end_matches('/')),
                    Err(err) => panic!("This build of A/B Street stores player data in $HOME/.abstreet, but $HOME isn't set: {}", err),
                }
            } else if cfg!(target_arch = "wasm32") {
                "../data".to_string()
            } else if file_exists("data/".to_string()) {
                "data".to_string()
            } else if file_exists("../data/".to_string()) {
                "../data".to_string()
            } else if file_exists("../../data/".to_string()) {
                "../../data".to_string()
            } else if file_exists("../../../data/".to_string()) {
                "../../../data".to_string()
            } else {
                panic!("Can't find the data/ directory");
            }
        });
        format!("{dir}/{p}")
    } else {
        let dir = ROOT_DIR.get_or_init(|| {

View on GitHub (pinned to 0964f29315)