{"record":{"id":"eb0506028d423b1f","repo":"unicity-aos/aos-ce","slug":"aos-mcp-malformed-host-hook-bridge-response-error","errorCode":null,"errorMessage":"aos-mcp: malformed host-hook bridge response: {error}","messagePattern":"aos-mcp: malformed host-hook bridge response: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"capsules/capsule-mcp/src/host_hooks.rs","lineNumber":124,"sourceCode":"            host: &request.host,\n            session_id: &request.session_id,\n            event: &request.event,\n            correlation_id: &request.correlation_id,\n            route_id: &request.route_id,\n            delivery_id: &request.delivery_id,\n            turn_id: request.turn_id.as_deref(),\n            workspace_id: request.workspace_id.as_deref(),\n            payload: &request.payload,\n        },\n    )\n}\n\npub(crate) fn relay_response(payload: serde_json::Value) -> Result<(), SysError> {\n    let response: HostHookResponse = match serde_json::from_value(payload) {\n        Ok(response) => response,\n        Err(error) => {\n            reject(\"unknown\", \"unknown\", \"malformed_response\");\n            log::warn(format!(\n                \"aos-mcp: malformed host-hook bridge response: {error}\"\n            ));\n            return Ok(());\n        }\n    };\n    let event = response.event.as_deref().unwrap_or(\"unknown\");\n    if let Err(reason) = validate_response_shape(&response) {\n        reject(&response.host, event, reason);\n        return Ok(());\n    }\n\n    let caller = match runtime::caller() {\n        Ok(caller) => caller,\n        Err(error) => {\n            reject(&response.host, event, \"caller_unavailable\");\n            log::warn(format!(\n                \"aos-mcp: caller unavailable for host-hook response: {error}\"\n            ));","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-mcp/src/host_hooks.rs#L106-L142","documentation":"relay_response deserializes the host-hook bridge response payload into HostHookResponse. On serde failure it rejects with `malformed_response` (host/event \"unknown\"), logs a warning with the serde error, and returns Ok(()) — the response is dropped rather than relayed to a mismatched structure.","triggerScenarios":"relay_response(payload) receives JSON that doesn't match HostHookResponse: missing principal_id, wrong event/host types, or non-JSON bytes.","commonSituations":"Host bridge emitting a response schema from an older/newer version, truncation or corruption of the payload in transit, or a bridge bug serializing optional fields incorrectly.","solutions":["Fix the bridge's response payload to match HostHookResponse (host, event, principal_id, etc.).","Check version alignment between the host bridge and the MCP capsule's response schema.","Log/inspect the raw payload on the bridge side to spot truncation or encoding problems."],"exampleFix":"// before (bridge)\nrespond(json!({ \"host\": host }))\n// after\nrespond(json!({ \"host\": host, \"event\": event, \"principal_id\": principal_id }))","handlingStrategy":"try-catch","validationCode":"// Bridge side: verify response shape before delivering\nif resp.get(\"principal_id\").is_none() {\n    return Err(\"host-hook response missing principal_id\");\n}","typeGuard":"fn is_valid_hook_response(v: &serde_json::Value) -> bool {\n    v.get(\"host\").and_then(|h| h.as_str()).is_some()\n        && v.get(\"principal_id\").and_then(|p| p.as_str()).is_some()\n}","tryCatchPattern":"match serde_json::from_value::<HostHookResponse>(payload) {\n    Ok(resp) => relay(resp),\n    Err(e) => { reject(\"unknown\", \"unknown\", \"malformed_response\"); log::warn!(\"malformed response: {e}\"); }\n}","preventionTips":["Keep the bridge's response serializer on the same version of the schema as the capsule.","Add round-trip serialization tests for HostHookResponse.","Watch malformed_response rejection logs for bridge regressions."],"tags":["serde","json","host-hooks","mcp","response"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}