{"record":{"id":"9785877d1301ff5f","repo":"astrid-runtime/astrid","slug":"shutdown-stage-daemon-shutdown-ack-unexpected-res","errorCode":null,"errorMessage":"shutdown stage daemon.shutdown_ack: unexpected response: {other:?}","messagePattern":"shutdown stage daemon\\.shutdown_ack: unexpected response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/daemon.rs","lineNumber":774,"sourceCode":"    if socket_present && let Ok(client) = socket_client::connect_kernel_for_recovery().await {\n        let mut client = client.with_timeout(Duration::from_secs(10));\n        let response = client\n            .request(KernelRequest::Shutdown {\n                reason: Some(\"astrid stop\".to_string()),\n            })\n            .await\n            .context(\"shutdown stage daemon.shutdown_ack\")?;\n        let disposition = match response {\n            KernelResponse::Success(_) => {\n                // ACK only — confirm the process actually exits before\n                // declaring success, and escalate if it wedged.\n                confirm_graceful_stop(recorded, &socket_path, &pid_path).await?\n            },\n            KernelResponse::Error(reason) => {\n                anyhow::bail!(\"shutdown stage daemon.shutdown_ack: rejected: {reason}\")\n            },\n            other => {\n                anyhow::bail!(\"shutdown stage daemon.shutdown_ack: unexpected response: {other:?}\")\n            },\n        };\n        cleanup_daemon_runtime(&socket_path, &pid_path).await?;\n        return Ok(disposition);\n    }\n\n    // Orphan path: the socket is present but unreachable (hung/half-dead\n    // daemon), OR the socket is already gone but a live recorded daemon is still\n    // holding the lock. A clean shutdown request is impossible either way, so\n    // signal the recorded PID (identity-gated) and clean up. Using the PID we\n    // captured up front — not a re-read — closes the window where the daemon\n    // deletes its own PID file mid-wedge.\n    let outcome = match recorded.as_ref() {\n        Some(identity) => daemon_control::terminate_identity(identity, &pid_path).await,\n        None => daemon_control::KillOutcome::NotRunning,\n    };\n    let disposition = confirm_kill_outcome(outcome)?;\n    cleanup_daemon_runtime(&socket_path, &pid_path).await?;","sourceCodeStart":756,"sourceCodeEnd":792,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/daemon.rs#L756-L792","documentation":"stop_daemon expects an ACK (Success) or an explicit rejection (Error) for a Shutdown request; any other KernelResponse variant is a protocol anomaly. The CLI bails with the staged message and the debug form of the response, indicating the daemon (or something answering on its socket) does not speak the expected shutdown protocol.","triggerScenarios":"Graceful stop path: connect_kernel_for_recovery succeeds and the Shutdown request is answered with a KernelResponse variant that is neither Success nor Error — e.g. Status, or a response type from a mismatched daemon version.","commonSituations":"CLI/daemon version skew after an upgrade with the old daemon still running; a different process bound to the socket path answering requests; a proxy/gateway intercepting and replying with its own variant set.","solutions":["Run `astrid restart` to replace a version-skewed or foreign daemon with one matching the CLI.","Verify which binary owns the recorded PID (ps -p <pid> -o cmdline) — an unrelated process may hold the socket.","Reinstall so CLI and daemon share one build/protocol version.","Check for another astrid home/AX_HOME pointing the CLI at a different daemon's socket."],"exampleFix":"// before\nError: shutdown stage daemon.shutdown_ack: unexpected response: Status(DaemonStatus { ... })\n// after\n$ astrid restart   # align daemon protocol with CLI\n$ astrid stop","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"fn is_ack_or_error(resp: &KernelResponse) -> bool {\n    matches!(resp, KernelResponse::Success(_) | KernelResponse::Error(_))\n}","tryCatchPattern":"match stop_daemon().await {\n    Err(e) if e.to_string().contains(\"daemon.shutdown_ack: unexpected response\") => {\n        eprintln!(\"protocol mismatch on shutdown: {e}\");\n        run(vec![\"astrid\", \"restart\"])?; // respawn matching daemon\n    }\n    r => r?,\n}","preventionTips":["Restart the daemon after every CLI upgrade to keep the protocol in sync.","Verify the socket is owned by a real astrid daemon (check the recorded PID's cmdline).","Avoid routing astrid socket traffic through custom proxies that emit foreign response variants.","Confirm AX_HOME points at the intended daemon's run-dir."],"tags":["daemon","shutdown","protocol","version-skew"],"backgroundTag":"unexpected-response-shape","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}