{"record":{"id":"c4a8c6be5b5df444","repo":"jlcodes99/cockpit-tools","slug":"ws-c4a8c6","errorCode":null,"errorMessage":"[WS] 处理消息失败: {}","messagePattern":"\\[WS\\] 处理消息失败: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cockpit-core/src/modules/websocket.rs","lineNumber":559,"sourceCode":"    // 发送 Ready 消息\n    let ready_msg = WsMessage::Ready {\n        version: env!(\"CARGO_PKG_VERSION\").to_string(),\n    };\n    if let Ok(json) = serde_json::to_string(&ready_msg) {\n        let _ = ws_sender.send(Message::Text(json.into())).await;\n    }\n\n    // 订阅广播\n    let mut broadcast_rx = server.tx.subscribe();\n\n    loop {\n        tokio::select! {\n            // 接收客户端消息\n            msg = ws_receiver.next() => {\n                match msg {\n                    Some(Ok(Message::Text(text))) => {\n                        if let Err(e) = handle_client_message(&server, &mut ws_sender, &text).await {\n                            crate::modules::logger::log_error(&format!(\"[WS] 处理消息失败: {}\", e));\n                        }\n                    }\n                    Some(Ok(Message::Close(_))) => {\n                        crate::modules::logger::log_info(&format!(\"[WS] 客户端断开: {}\", addr));\n                        break;\n                    }\n                    Some(Err(e)) => {\n                        crate::modules::logger::log_error(&format!(\"[WS] 接收错误 {}: {}\", addr, e));\n                        break;\n                    }\n                    None => break,\n                    _ => {}\n                }\n            }\n            // 发送广播消息\n            msg = broadcast_rx.recv() => {\n                if let Ok(json) = msg {\n                    if ws_sender.send(Message::Text(json.into())).await.is_err() {","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/websocket.rs#L541-L577","documentation":"Logged when handle_client_message(&server, &mut ws_sender, &text) returns Err while processing a Text frame from a client. handle_client_message parses and dispatches client messages and may reply over ws_sender; any failure there (bad payload, unhandled/unknown message type, or failure sending the response frame) surfaces here. Only the failed message is affected — the select! loop continues and the connection stays open.","triggerScenarios":"A client sends a Message::Text whose content cannot be handled: invalid JSON, missing/unknown message type field, a request referencing nonexistent state, or the response write on ws_sender fails because the client already went away.","commonSituations":"A VS Code/extension client and backend disagreeing on the message schema after a version change; hand-written test clients sending malformed JSON; clients disconnecting mid-request so the reply send fails; typos in the message 'type' field.","solutions":["Inspect the logged error to see whether it is a parse (JSON/schema) error or a send failure.","Log/inspect the raw text frame on the client side and validate it against the expected message schema before sending.","Rebuild/reload the client extension so client and server use the same message protocol version.","If it is a send error, treat it as a disconnect: close and reconnect the client socket."],"exampleFix":"// before: sending an unversioned/unknown payload\nws.send(JSON.stringify({ cmd: \"startThing\" }))\n// after: match the expected schema with a known type field\nws.send(JSON.stringify({ type: \"start\", payload: { id: 1 } }))","handlingStrategy":"try-catch","validationCode":"// client side: validate the message before sending\nfunction isValidMessage(m) {\n  return typeof m === \"object\" && m !== null\n    && typeof m.type === \"string\" && m.type.length > 0;\n}\nconst msg = { type: \"start\", payload: { id: 1 } };\nif (!isValidMessage(msg)) throw new Error(\"invalid WS message\");\nws.send(JSON.stringify(msg));","typeGuard":"fn is_known_type(t: &str) -> bool {\n    matches!(t, \"start\" | \"stop\" | \"status\" | \"config\")\n}","tryCatchPattern":"match handle_client_message(&server, &mut ws_sender, &text).await {\n    Ok(()) => {}\n    Err(e) => {\n        log_error(&format!(\"[WS] 处理消息失败: {}\", e));\n        // keep the connection open; optionally send an error frame back to the client\n        let _ = ws_sender.send(Message::Text(format!(\"{{\\\"error\\\":\\\"{}\\\"}}\", e))).await;\n    }\n}","preventionTips":["Version the WS message schema and validate payloads on both sides before dispatch.","Keep a single shared definition of message types between extension and backend.","Log the offending raw text at debug level to speed up schema-mismatch diagnosis.","Send an explicit error frame to the client instead of silently dropping bad messages."],"tags":["websocket","message-handling","rust"],"backgroundTag":"websocket-message-handling-failed","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}