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

  1. Set `ASTRID_HOME` to an absolute, user-owned, non-world-listable directory (e.g. `export ASTRID_HOME=$HOME/.astrid`).
  2. Fix the invalid value currently in `ASTRID_HOME` (check for typos, empty string, or relative paths) in your shell profile or service unit.
  3. Ensure the referenced directory exists or can be created with correct ownership (not world-readable, since the token must stay private).
  4. If running under a service account, provision a home directory for it or set `ASTRID_HOME` explicitly in the unit file.
  5. 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

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


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)