{"record":{"id":"6c872f308797a2fc","repo":"astrid-runtime/astrid","slug":"kernel-returned-an-unexpected-projection-name-diag","errorCode":null,"errorMessage":"kernel returned an unexpected projection-name diagnostic response","messagePattern":"kernel returned an unexpected projection-name diagnostic response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-uplink/src/kernel_client.rs","lineNumber":345,"sourceCode":"            \"params\": { \"policy\": policy },\n        });\n        let (message, response_topic) = build_named_request_message(\n            &self.caller,\n            self.device_key_id.as_deref(),\n            PROJECTION_NAME_DIAGNOSTIC_TOPIC,\n            payload,\n        );\n        match self\n            .send_and_wait(message, response_topic, MAX_TOTAL)\n            .await?\n        {\n            KernelResponse::Success(value) => {\n                serde_json::from_value(value).context(\"decode projection-name diagnostic response\")\n            },\n            KernelResponse::Error(message) => Err(anyhow!(\n                \"kernel rejected projection-name diagnostic: {message}\"\n            )),\n            _ => Err(anyhow!(\n                \"kernel returned an unexpected projection-name diagnostic response\"\n            )),\n        }\n    }\n\n    /// [`request`](Self::request) with an explicit overall ceiling.\n    ///\n    /// The public entrypoint passes [`MAX_TOTAL`]; a test passes a short ceiling\n    /// so the \"unending keepalives are bounded\" path is exercisable without\n    /// waiting ten minutes. Production behaviour is unchanged.\n    async fn request_with_ceiling(\n        &mut self,\n        req: KernelRequest,\n        max_total: Duration,\n    ) -> std::result::Result<KernelResponse, KernelClientError> {\n        let (msg, want_response) =\n            build_request_message(&self.caller, self.device_key_id.as_deref(), &req)\n                .map_err(|source| KernelClientError::Build { source })?;","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-uplink/src/kernel_client.rs#L327-L363","documentation":"Raised by the public method `projection_name_diagnostic` in `astrid-uplink/src/kernel_client.rs:345`. When the awaited reply is neither `KernelResponse::Success` nor `KernelResponse::Error` — falling into the catch-all `_` arm — the client cannot interpret the kernel's response shape and throws this error. It indicates a protocol violation or version mismatch between the client and the kernel on the diagnostic response channel.","triggerScenarios":"Specifically: `send_and_wait` for the projection-name diagnostic returns a `KernelResponse` variant outside `{Success, Error}` (e.g. an event/other frame type arrived on the response topic), so the match falls through to the wildcard arm. Cross-talk on the response topic or an unexpected kernel frame can also land here.","commonSituations":"Client and kernel built from mismatched versions where the diagnostic reply encoding changed; another message was routed to the same response topic and matched first; a kernel bug emitting a non-standard frame for this request; multiplexed topics where two in-flight diagnostics share a topic string.","solutions":["Upgrade the astrid-uplink client and kernel daemon to matching versions so the diagnostic response schema agrees.","Ensure each request uses a unique response topic so no other kernel frame can be matched against it.","Log the actual `KernelResponse` variant received (add a debug print before the match) to identify what the kernel returned.","Retry once after re-establishing the socket in case a stale/misrouted frame was in flight; if it persists, file a protocol bug."],"exampleFix":"// before\nKernelResponse::Error(message) => Err(anyhow!(\n    \"kernel rejected projection-name diagnostic: {message}\"\n)),\n_ => Err(anyhow!(\n    \"kernel returned an unexpected projection-name diagnostic response\"\n)),\n// after (make the unexpected case debuggable)\n_ => {\n    debug!(?response, \"unexpected projection-name diagnostic response\");\n    Err(anyhow!(\n        \"kernel returned an unexpected projection-name diagnostic response: {response:?}\"\n    ))\n}","handlingStrategy":"type-guard","validationCode":"// Ensure a dedicated response topic per request to avoid cross-talk\nlet response_topic = format!(\"diag/{}/{}\", Uuid::new_v4(), name);","typeGuard":"fn matches_diag_response(resp: &KernelResponse) -> bool {\n    matches!(resp, KernelResponse::Success(_) | KernelResponse::Error(_))\n}","tryCatchPattern":"let resp = send_and_wait(message, response_topic, MAX_TOTAL).await?;\nif !matches_diag_response(&resp) {\n    debug!(?resp, \"unexpected kernel response shape\");\n    bail!(\"kernel returned an unexpected projection-name diagnostic response: {resp:?}\");\n}","preventionTips":["Use a unique response topic per in-flight request so unrelated kernel frames cannot be misinterpreted.","Pin client and kernel to the same release train; response framing changed across versions historically.","Log unexpected variants at debug level to make protocol skew visible in the field."],"tags":["kernel","ipc","protocol","rpc","version-skew"],"backgroundTag":"unexpected-api-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"}