{"record":{"id":"ff6d0ed193d200e9","repo":"astrid-runtime/astrid","slug":"failed-to-resolve-astrid-home-for-handshake-e","errorCode":null,"errorMessage":"Failed to resolve ASTRID_HOME for handshake: {e}","messagePattern":"Failed to resolve ASTRID_HOME for handshake: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-uplink/src/socket_client.rs","lineNumber":496,"sourceCode":"///\n/// Two flows, picked by key presence:\n/// - **Authenticated (two frames):** when `keys/<principal>.key` exists, the\n///   first request frame carries `claimed_principal` (no signature); the\n///   daemon replies with a challenge nonce; a second frame carries the\n///   ed25519 signature over\n///   `astrid-principal-auth:v1:{principal}:{nonce_hex}`.\n/// - **Legacy (single frame):** when no key file exists, the request omits\n///   `claimed_principal` and the handshake completes in one round trip,\n///   preserving behaviour for callers without a key.\n///\n/// Returns `true` when the connection authenticated as `principal` via the\n/// signed challenge (the daemon bound it to that identity), `false` when it\n/// took the legacy single-frame path that the daemon stamps the no-capability\n/// `anonymous`. An outright-rejected handshake (e.g. a bad signature) is an\n/// `Err`, never a silent `false`.\nasync fn perform_handshake(stream: &mut LocalStream, principal: &PrincipalId) -> Result<bool> {\n    let home = astrid_core::dirs::AstridHome::resolve()\n        .map_err(|e| anyhow::anyhow!(\"Failed to resolve ASTRID_HOME for handshake: {e}\"))?;\n    perform_handshake_in_home(stream, principal, &home).await\n}\n\npub(crate) async fn perform_handshake_in_home(\n    stream: &mut LocalStream,\n    principal: &PrincipalId,\n    home: &astrid_core::dirs::AstridHome,\n) -> Result<bool> {\n    let tok_path = home.token_path();\n    let token = SessionToken::read_from_file(&tok_path).with_context(|| {\n        format!(\n            \"Failed to read session token from {}. Is the daemon running?\",\n            tok_path.display()\n        )\n    })?;\n\n    // Load the signing key only if it exists; absence ⇒ legacy single-frame.\n    let keypair = {","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-uplink/src/socket_client.rs#L478-L514","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: connect fails with unresolved ASTRID_HOME\nexport ASTRID_HOME=/opt/astrid  # directory does not exist\nastrid uplink connect\n\n// after\nmkdir -p /opt/astrid && astrid init   # or: unset ASTRID_HOME to use default\nastrid uplink connect","handlingStrategy":"validation","validationCode":"// shell, before launching the client\nif [ -n \"$ASTRID_HOME\" ] && [ ! -d \"$ASTRID_HOME\" ]; then\n  echo \"ASTRID_HOME=$ASTRID_HOME does not exist\" >&2; exit 1\nfi","typeGuard":"null","tryCatchPattern":"null","preventionTips":["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."],"tags":["configuration","environment","handshake","rust"],"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"}