astrid-runtime/astrid · error

Failed to resolve ASTRID_HOME for handshake

Error message

Failed to resolve ASTRID_HOME for handshake: {e}

What it means

`perform_handshake` must resolve the ASTRID_HOME directory (via `astrid_core::dirs::AstridHome::resolve()`) before it can locate the identity material needed for the authenticated handshake. If resolution fails (e.g. ASTRID_HOME points nowhere or is not derivable), the whole `connect` call fails with this message. It is a fail-fast check: the handshake itself never runs without a valid home.

Solutions

  1. Check the ASTRID_HOME environment variable: unset it to fall back to the default location, or set it to an existing, accessible directory.
  2. Create/initialize the astrid home directory (`mkdir -p "$ASTRID_HOME"` and run the daemon's init/first-run) before connecting.
  3. Fix filesystem permissions so the current user can read/write the resolved home directory.
  4. If resolution is supposed to succeed, verify the underlying error text (chained as source of this anyhow error) for the exact cause.

Example fix

// before: connect fails with unresolved ASTRID_HOME
export ASTRID_HOME=/opt/astrid  # directory does not exist
astrid uplink connect

// after
mkdir -p /opt/astrid && astrid init   # or: unset ASTRID_HOME to use default
astrid uplink connect
Defensive patterns

Strategy: validation

Validate before calling

// shell, before launching the client
if [ -n "$ASTRID_HOME" ] && [ ! -d "$ASTRID_HOME" ]; then
  echo "ASTRID_HOME=$ASTRID_HOME does not exist" >&2; exit 1
fi

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling `connect` (which invokes `perform_handshake`) while `AstridHome::resolve()` errors — ASTRID_HOME env var set to a nonexistent path, unwritable/undeterminable home directory, or malformed ASTRID_HOME.

Common situations: Running the client in a container/CI where ASTRID_HOME is set but the directory was not mounted; a typo'd ASTRID_HOME value; running as a different user whose home cannot be resolved; first-run setup never initialized the astrid home.

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/ff6d0ed193d200e9. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-uplink/src/socket_client.rs:496

///
/// Two flows, picked by key presence:
/// - **Authenticated (two frames):** when `keys/<principal>.key` exists, the
///   first request frame carries `claimed_principal` (no signature); the
///   daemon replies with a challenge nonce; a second frame carries the
///   ed25519 signature over
///   `astrid-principal-auth:v1:{principal}:{nonce_hex}`.
/// - **Legacy (single frame):** when no key file exists, the request omits
///   `claimed_principal` and the handshake completes in one round trip,
///   preserving behaviour for callers without a key.
///
/// Returns `true` when the connection authenticated as `principal` via the
/// signed challenge (the daemon bound it to that identity), `false` when it
/// took the legacy single-frame path that the daemon stamps the no-capability
/// `anonymous`. An outright-rejected handshake (e.g. a bad signature) is an
/// `Err`, never a silent `false`.
async fn perform_handshake(stream: &mut LocalStream, principal: &PrincipalId) -> Result<bool> {
    let home = astrid_core::dirs::AstridHome::resolve()
        .map_err(|e| anyhow::anyhow!("Failed to resolve ASTRID_HOME for handshake: {e}"))?;
    perform_handshake_in_home(stream, principal, &home).await
}

pub(crate) async fn perform_handshake_in_home(
    stream: &mut LocalStream,
    principal: &PrincipalId,
    home: &astrid_core::dirs::AstridHome,
) -> Result<bool> {
    let tok_path = home.token_path();
    let token = SessionToken::read_from_file(&tok_path).with_context(|| {
        format!(
            "Failed to read session token from {}. Is the daemon running?",
            tok_path.display()
        )
    })?;

    // Load the signing key only if it exists; absence ⇒ legacy single-frame.
    let keypair = {

View on GitHub (pinned to affd8760f4)