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
- Check the ASTRID_HOME environment variable: unset it to fall back to the default location, or set it to an existing, accessible directory.
- Create/initialize the astrid home directory (`mkdir -p "$ASTRID_HOME"` and run the daemon's init/first-run) before connecting.
- Fix filesystem permissions so the current user can read/write the resolved home directory.
- 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
- Never set ASTRID_HOME unless the directory exists and is initialized.
- Run the daemon's init/first-run step as part of environment/container setup.
- Ensure the client runs as a user with read/write access to the astrid home.
- In CI, explicitly create and export ASTRID_HOME before any connect call.
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.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- canonical Astrid workspace requires the kernel workspace…
- duplicate corpus label
- Failed to resolve ASTRID_HOME for token path
- gateway is not wired to a live audit log; historical-query…
- gateway is not wired to a live event bus; agent approval…
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)