astrid-runtime/astrid · error
Failed to resolve ASTRID_HOME for token path
Error message
Failed to resolve ASTRID_HOME for token path: {e} What it means
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}`.
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.
Example fix
// before (environment) ASTRID_HOME= astrid status # empty ASTRID_HOME breaks token_path() // after export ASTRID_HOME="$HOME/.astrid" mkdir -p "$ASTRID_HOME" && chmod 700 "$ASTRID_HOME" astrid status
Defensive patterns
Strategy: validation
Validate before calling
use std::env;
fn astrid_home_ready() -> Result<(), String> {
match env::var("ASTRID_HOME") {
Ok(v) if v.is_empty() => Err("ASTRID_HOME is set but empty".into()),
Ok(v) => {
let p = std::path::PathBuf::from(v);
if p.is_absolute() { Ok(()) } else { Err(format!("ASTRID_HOME {v:?} is not absolute")) }
},
Err(env::VarError::NotPresent) => Err("ASTRID_HOME is not set".into()),
Err(e) => Err(format!("ASTRID_HOME unreadable: {e}")),
}
} Type guard
fn env_var_usable(name: &str) -> bool {
std::env::var(name).map(|v| !v.is_empty()).unwrap_or(false)
}
if !env_var_usable("ASTRID_HOME") { eprintln!("set ASTRID_HOME before invoking the client"); } Try / catch
let path = match socket_client::token_path() {
Ok(p) => p,
Err(e) => {
eprintln!("cannot locate session token (ASTRID_HOME unresolved): {e:#}");
std::process::exit(2);
}
}; Prevention
- 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.
When it happens
Trigger: 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.
Common situations: `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.
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
- resolve $ASTRID_HOME for revocation file
- Failed to resolve ASTRID_HOME for handshake
- named-pipe client's effective token belongs to a different…
- required environment variable ASTRID_HOOK_TOKEN is missing…
- Astrid volume path has no file name
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/0ce068403046378a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-uplink/src/socket_client.rs:91
match AstridHome::resolve() {
Ok(home) => home.pid_path(),
Err(e) => {
warn!(error = %e, "Failed to resolve ASTRID_HOME; falling back to /tmp/.astrid/run/system.pid");
std::path::PathBuf::from("/tmp/.astrid/run/system.pid")
},
}
}
/// Path to the session-authentication token file.
///
/// # Errors
/// Returns an error if `ASTRID_HOME` cannot be resolved. No `/tmp`
/// fallback — the daemon refuses to write its token under
/// world-listable directories.
pub fn token_path() -> Result<std::path::PathBuf> {
use astrid_core::dirs::AstridHome;
let home = AstridHome::resolve()
.map_err(|e| anyhow::anyhow!("Failed to resolve ASTRID_HOME for token path: {e}"))?;
Ok(home.token_path())
}
/// Why a [`SocketClient::read_until_topic_typed`] read ended without the
/// awaited frame.
///
/// The two cases demand different recovery: a [`ConnectionLost`](Self::ConnectionLost)
/// means the socket is dead and the caller should reconnect (and, for an
/// idempotent request, retry); a [`Timeout`](Self::Timeout) means the deadline
/// elapsed while the connection was still open — the broker is merely slow, so
/// the caller must NOT reconnect (the request may still be in flight).
#[derive(Debug)]
pub enum ReadError {
/// The socket reached EOF or a read failed (peer closed / reset / broken
/// pipe). The connection is unusable; reconnect before the next request.
ConnectionLost(anyhow::Error),
/// The deadline elapsed with the connection still open. Do not reconnect.
Timeout,View on GitHub (pinned to affd8760f4)