{"record":{"id":"def341f15d071b51","repo":"jlcodes99/cockpit-tools","slug":"url-def341","errorCode":null,"errorMessage":"网关 {} 响应解析失败: {} (url={})","messagePattern":"网关 (.+?) 响应解析失败: (.+?) \\(url=(.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/modules/wakeup.rs","lineNumber":776,"sourceCode":"        crate::modules::logger::log_error(&format!(\n            \"[Wakeup] 网关 {} 返回错误: url={}, status={}, body_len={}, body={}\",\n            op_name,\n            url,\n            status,\n            summarize_body_len(&text),\n            truncate_log_text(&text, 512)\n        ));\n        return Err(format!(\n            \"网关 {} 返回错误: status={}, body_len={}\",\n            op_name,\n            status,\n            summarize_body_len(&text)\n        ));\n    }\n\n    serde_json::from_str::<serde_json::Value>(&text).map_err(|e| {\n        let message = format!(\"网关 {} 响应解析失败: {} (url={})\", op_name, e, url);\n        crate::modules::logger::log_error(&format!(\n            \"[Wakeup] {}，body_len={}\",\n            message,\n            summarize_body_len(&text)\n        ));\n        message\n    })\n}\n\nasync fn resolve_requested_model_for_official_ls(\n    account_id: &str,\n    model: &str,\n    cancel_rx: Option<&watch::Receiver<bool>>,\n) -> Result<serde_json::Value, String> {\n    let trimmed = model.trim();\n    if let Ok(num) = trimmed.parse::<i64>() {\n        return Ok(json!({ \"model\": num }));\n    }\n","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src-tauri/src/modules/wakeup.rs#L758-L794","documentation":"post_gateway_json got a 2xx response but serde_json::from_str failed to parse the body as JSON, so it returns '网关 {op} 响应解析失败: {parse_err} (url={url})'. The gateway returned a non-JSON body (or invalid JSON) where a JSON payload was expected, e.g. an HTML error page or empty body.","triggerScenarios":"trigger_wakeup_via_client_gateway_once → post_gateway_json receives text that isn't valid JSON — a proxy/HTML error page served with 200, an empty body, a truncated response, or a gateway returning plain text.","commonSituations":"Captive portal/corporate proxy injecting HTML; gateway returning empty 200 on internal error; compression/charset mismatch corrupting the body; gateway API version returning a different content type; response cut off by timeout mid-body.","solutions":["Log/inspect the truncated body (already truncated to 512 chars) to see what was actually returned","Check for a proxy/VPN injecting HTML error pages into 200 responses","Confirm the gateway endpoint version matches what this client expects","Retry — transient truncation or gateway glitch may resolve","Handle the empty-body case explicitly before parsing"],"exampleFix":"// before\nserde_json::from_str::<serde_json::Value>(&text).map_err(|e| {\n    let message = format!(\"网关 {} 响应解析失败: {} (url={})\", op_name, e, url);\n    ...\n})\n// after\nif text.trim().is_empty() {\n    return Err(format!(\"网关 {} 响应为空 (url={})\", op_name, url));\n}\nserde_json::from_str::<serde_json::Value>(&text).map_err(|e| {\n    let message = format!(\"网关 {} 响应解析失败: {} (url={})\", op_name, e, url);\n    ...\n})","handlingStrategy":"validation","validationCode":"// Guard the response before parsing\nfn is_parseable_json(text: &str) -> bool {\n    let t = text.trim();\n    !t.is_empty() && (t.starts_with('{') || t.starts_with('[')) && serde_json::from_str::<serde_json::Value>(t).is_ok()\n}","typeGuard":"fn as_json(text: &str) -> Option<serde_json::Value> {\n    serde_json::from_str::<serde_json::Value>(text).ok()\n}","tryCatchPattern":"match post_gateway_json(...).await {\n    Err(e) if e.contains(\"响应解析失败\") => {\n        // inspect logged body snippet; likely proxy HTML or empty body — retry via alternate base\n        try_next_base_url().await;\n    }\n    other => handle(other),\n}","preventionTips":["Check Content-Type is application/json before parsing","Explicitly handle empty bodies instead of attempting JSON parse","Bypass/inspect corporate proxies that inject HTML into responses","Fuzz/contract-test against real gateway responses on version upgrades"],"tags":["gateway","json","parse-error","api-response"],"backgroundTag":"json-parse-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"}