{"record":{"id":"6e28b6a737a7a607","repo":"astrid-runtime/astrid","slug":"running-daemon-returned-unload-success-without-a-s","errorCode":null,"errorMessage":"running daemon returned unload success without a status","messagePattern":"running daemon returned unload success without a status","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/capsule/live_load.rs","lineNumber":166,"sourceCode":"        session_uuid,\n    );\n    client\n        .send_message(msg)\n        .await\n        .context(\"failed to send live capsule unload request\")?;\n\n    let raw = client\n        .read_until_topic(response_topic.as_str(), std::time::Duration::from_secs(15))\n        .await\n        .context(\"running daemon did not confirm live capsule unload\")?;\n\n    match crate::socket_client::SocketClient::extract_kernel_response(&raw) {\n        Some(KernelResponse::Success(data)) => {\n            match data.get(\"status\").and_then(serde_json::Value::as_str) {\n                Some(\"unloaded\") => Ok(LiveUnload::Unloaded),\n                Some(\"not_loaded\") => Ok(LiveUnload::NotLoaded),\n                Some(other) => bail!(\"running daemon returned unknown unload status {other:?}\"),\n                None => bail!(\"running daemon returned unload success without a status\"),\n            }\n        },\n        Some(KernelResponse::Error(reason)) => {\n            bail!(\"running daemon declined live capsule unload: {reason}\")\n        },\n        _ => bail!(\"running daemon returned a malformed live capsule unload response\"),\n    }\n}\n\nasync fn daemon_socket_reachable() -> bool {\n    let path = crate::socket_client::proxy_socket_path();\n    matches!(\n        astrid_core::local_transport::connect_outcome(&path).await,\n        Ok(astrid_core::local_transport::ConnectOutcome::Connected(_))\n    )\n}\n\nfn classify_live_client<T>(","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/capsule/live_load.rs#L148-L184","documentation":"This error is thrown by try_daemon_unload when the running daemon replied with a KernelResponse::Success payload for an UnloadCapsule request, but the JSON payload lacks a 'status' string field. The CLI distinguishes 'unloaded' from 'not_loaded' via that field; without it the outcome is ambiguous, so the CLI refuses to guess and reports a protocol violation. It indicates a daemon/CLI version mismatch or a daemon bug rather than a problem with the capsule itself.","triggerScenarios":"Issuing a live unload (astrid capsule live-unload) while a daemon is running; the daemon returns Success but its JSON body has no 'status' key (e.g. an older daemon or custom kernel build that omits the field).","commonSituations":"Daemon and CLI were upgraded independently so their IPC schema drifted; a third-party or patched daemon responds with an empty Success object; a proxy on the socket rewrites the response payload.","solutions":["Restart or upgrade the astrid daemon so it matches the CLI's expected IPC schema (Success payloads must include a string 'status' of 'unloaded' or 'not_loaded').","Check daemon and CLI versions and reinstall them from the same release.","Retry the unload after the daemon is updated; the file-state unload path can still be used if the daemon path keeps failing."],"exampleFix":"// daemon side, before\nOk(json!({\"capsule\": id}))\n// after\nOk(json!({\"status\": \"unloaded\", \"capsule\": id}))","handlingStrategy":"type-guard","validationCode":"// before trusting a daemon Success payload\nfn has_unload_status(v: &serde_json::Value) -> bool {\n    matches!(v.get(\"status\"), Some(s) if s.is_string())\n}","typeGuard":"fn unload_status(v: &serde_json::Value) -> Option<&str> {\n    v.get(\"status\").and_then(serde_json::Value::as_str)\n      .filter(|s| matches!(*s, \"unloaded\" | \"not_loaded\"))\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"without a status\") => {\n        // fall back to offline uninstall or prompt a daemon upgrade\n    }\n    Err(e) => return Err(e),\n    Ok(outcome) => handle(outcome),\n}","preventionTips":["Pin CLI and daemon to the same release so the IPC schema matches.","After daemon upgrades, smoke-test live load/unload before relying on it.","Log full daemon responses when debugging protocol drift."],"tags":["ipc","protocol","daemon"],"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"}