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
- 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=...)
- Rebuild without ABST_PLAYER_HOME_DIR so the library falls back to the data/-relative player dir instead of $HOME/.abstreet
- 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
- 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
- Always launch packaged (ABST_PLAYER_HOME_DIR) builds with HOME set in the service/unit/container environment
- Never build with ABST_PLAYER_HOME_DIR unless you control the runtime environment
- Prefer runtime env lookup (std::env::var or dirs crate) over option_env! for deployable builds
- Test packaged binaries under systemd/Docker environments where HOME is often unset
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
- Can't find the data/ directory
- CityName::new( , ) has a country code that isn't two letters
- Couldn't read_json( )
- Couldn't read_binary
- Couldn't read_object
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)