{"record":{"id":"423febaf79d67d50","repo":"a-b-street/abstreet","slug":"this-build-of-a-b-street-stores-player-data-in-home-abstreet","errorCode":null,"errorMessage":"This build of A/B Street stores player data in $HOME/.abstreet, but $HOME isn't set: {}","messagePattern":"This build of A/B Street stores player data in \\$HOME/\\.abstreet, but \\$HOME isn't set: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"abstio/src/abst_paths.rs","lineNumber":28,"sourceCode":"use serde::{Deserialize, Serialize};\n\nuse abstutil::basename;\n\nuse crate::{file_exists, list_all_objects, Manifest};\n\nstatic ROOT_DIR: OnceLock<String> = OnceLock::new();\nstatic ROOT_PLAYER_DIR: OnceLock<String> = OnceLock::new();\n\npub fn path<I: AsRef<str>>(p: I) -> String {\n    let p = p.as_ref();\n    if p.starts_with(\"player/\") {\n        let dir = ROOT_PLAYER_DIR.get_or_init(|| {\n            // If you're packaging for a release and want the player's local data directory to be\n            // $HOME/.abstreet, set ABST_PLAYER_HOME_DIR=1\n            if option_env!(\"ABST_PLAYER_HOME_DIR\").is_some() {\n                match std::env::var(\"HOME\") {\n                    Ok(dir) => format!(\"{}/.abstreet\", dir.trim_end_matches('/')),\n                    Err(err) => panic!(\"This build of A/B Street stores player data in $HOME/.abstreet, but $HOME isn't set: {}\", err),\n                }\n            } else if cfg!(target_arch = \"wasm32\") {\n                \"../data\".to_string()\n            } else if file_exists(\"data/\".to_string()) {\n                \"data\".to_string()\n            } else if file_exists(\"../data/\".to_string()) {\n                \"../data\".to_string()\n            } else if file_exists(\"../../data/\".to_string()) {\n                \"../../data\".to_string()\n            } else if file_exists(\"../../../data/\".to_string()) {\n                \"../../../data\".to_string()\n            } else {\n                panic!(\"Can't find the data/ directory\");\n            }\n        });\n        format!(\"{dir}/{p}\")\n    } else {\n        let dir = ROOT_DIR.get_or_init(|| {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/abst_paths.rs#L10-L46","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before (shell)\n./abstreet  # built with ABST_PLAYER_HOME_DIR=1, panics: HOME isn't set\n// after (shell)\nexport HOME=\"$HOME\"; ./abstreet\n# or rebuild:\nunset ABST_PLAYER_HOME_DIR && cargo build --release","handlingStrategy":"validation","validationCode":"if std::env::var_os(\"HOME\").map(|h| !h.is_empty()).unwrap_or(false) {\n    // safe to call abstio::path(\"player/...\") in an ABST_PLAYER_HOME_DIR build\n} else {\n    eprintln!(\"HOME must be set for player data\");\n}","typeGuard":"fn home_is_set() -> bool {\n    std::env::var_os(\"HOME\").map(|h| !h.is_empty()).unwrap_or(false)\n}","tryCatchPattern":"// Rust panics are not catchable via Result; wrap startup in catch_unwind if you must recover\nlet ok = std::panic::catch_unwind(|| abstio::path(\"player/settings.json\"));\nmatch ok {\n    Ok(p) => println!(\"player dir ok: {}\", p),\n    Err(_) => eprintln!(\"HOME not set; cannot use player data\"),\n}","preventionTips":["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"],"tags":["rust","panic","environment-variable","home-directory","packaging"],"backgroundTag":"missing-env-var","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}