{"record":{"id":"0ce068403046378a","repo":"astrid-runtime/astrid","slug":"failed-to-resolve-astrid-home-for-token-path-e","errorCode":null,"errorMessage":"Failed to resolve ASTRID_HOME for token path: {e}","messagePattern":"Failed to resolve ASTRID_HOME for token path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-uplink/src/socket_client.rs","lineNumber":91,"sourceCode":"    match AstridHome::resolve() {\n        Ok(home) => home.pid_path(),\n        Err(e) => {\n            warn!(error = %e, \"Failed to resolve ASTRID_HOME; falling back to /tmp/.astrid/run/system.pid\");\n            std::path::PathBuf::from(\"/tmp/.astrid/run/system.pid\")\n        },\n    }\n}\n\n/// Path to the session-authentication token file.\n///\n/// # Errors\n/// Returns an error if `ASTRID_HOME` cannot be resolved. No `/tmp`\n/// fallback — the daemon refuses to write its token under\n/// world-listable directories.\npub fn token_path() -> Result<std::path::PathBuf> {\n    use astrid_core::dirs::AstridHome;\n    let home = AstridHome::resolve()\n        .map_err(|e| anyhow::anyhow!(\"Failed to resolve ASTRID_HOME for token path: {e}\"))?;\n    Ok(home.token_path())\n}\n\n/// Why a [`SocketClient::read_until_topic_typed`] read ended without the\n/// awaited frame.\n///\n/// The two cases demand different recovery: a [`ConnectionLost`](Self::ConnectionLost)\n/// means the socket is dead and the caller should reconnect (and, for an\n/// idempotent request, retry); a [`Timeout`](Self::Timeout) means the deadline\n/// elapsed while the connection was still open — the broker is merely slow, so\n/// the caller must NOT reconnect (the request may still be in flight).\n#[derive(Debug)]\npub enum ReadError {\n    /// The socket reached EOF or a read failed (peer closed / reset / broken\n    /// pipe). The connection is unusable; reconnect before the next request.\n    ConnectionLost(anyhow::Error),\n    /// The deadline elapsed with the connection still open. Do not reconnect.\n    Timeout,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-uplink/src/socket_client.rs#L73-L109","documentation":"Raised by the public function `token_path` in `astrid-uplink/src/socket_client.rs:91` when `AstridHome::resolve()` fails while locating the per-session authentication token file. Unlike `pid_path`, there is deliberately no `/tmp` fallback: the token is a secret, and the daemon refuses to place it in world-listable directories. The resolver's own error is interpolated into the message via `{e}`.","triggerScenarios":"Specifically: calling `token_path()` when `ASTRID_HOME` cannot be resolved — e.g. the `ASTRID_HOME` environment variable points to an unusable path, is set to an invalid value, and no valid fallback home directory can be established on the platform.","commonSituations":"`ASTRID_HOME` exported with a typo or an empty value in the shell/systemd unit; the variable points to a path on an unmounted volume or one the user cannot create; running the client in a sanitized environment (CI container, `env -i`) where neither `ASTRID_HOME` nor a home directory is available; XDG/home resolution failing for a service account with no home dir.","solutions":["Set `ASTRID_HOME` to an absolute, user-owned, non-world-listable directory (e.g. `export ASTRID_HOME=$HOME/.astrid`).","Fix the invalid value currently in `ASTRID_HOME` (check for typos, empty string, or relative paths) in your shell profile or service unit.","Ensure the referenced directory exists or can be created with correct ownership (not world-readable, since the token must stay private).","If running under a service account, provision a home directory for it or set `ASTRID_HOME` explicitly in the unit file.","Read the inner `{e}` text to see which resolver step failed (env parse vs path creation) and address that specific cause."],"exampleFix":"// before (environment)\nASTRID_HOME= astrid status   # empty ASTRID_HOME breaks token_path()\n// after\nexport ASTRID_HOME=\"$HOME/.astrid\"\nmkdir -p \"$ASTRID_HOME\" && chmod 700 \"$ASTRID_HOME\"\nastrid status","handlingStrategy":"validation","validationCode":"use std::env;\nfn astrid_home_ready() -> Result<(), String> {\n    match env::var(\"ASTRID_HOME\") {\n        Ok(v) if v.is_empty() => Err(\"ASTRID_HOME is set but empty\".into()),\n        Ok(v) => {\n            let p = std::path::PathBuf::from(v);\n            if p.is_absolute() { Ok(()) } else { Err(format!(\"ASTRID_HOME {v:?} is not absolute\")) }\n        },\n        Err(env::VarError::NotPresent) => Err(\"ASTRID_HOME is not set\".into()),\n        Err(e) => Err(format!(\"ASTRID_HOME unreadable: {e}\")),\n    }\n}","typeGuard":"fn env_var_usable(name: &str) -> bool {\n    std::env::var(name).map(|v| !v.is_empty()).unwrap_or(false)\n}\nif !env_var_usable(\"ASTRID_HOME\") { eprintln!(\"set ASTRID_HOME before invoking the client\"); }","tryCatchPattern":"let path = match socket_client::token_path() {\n    Ok(p) => p,\n    Err(e) => {\n        eprintln!(\"cannot locate session token (ASTRID_HOME unresolved): {e:#}\");\n        std::process::exit(2);\n    }\n};","preventionTips":["Export ASTRID_HOME as an absolute, user-owned path in shell profiles and systemd units.","Never point ASTRID_HOME at world-listable locations; the token must stay private.","Check `env::var(\"ASTRID_HOME\")` before invoking client commands in scripts/CI.","Provision a home directory or explicit ASTRID_HOME for service accounts."],"tags":["environment","configuration","token","authentication","paths"],"backgroundTag":"missing-env-var","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}