{"record":{"id":"9aff8405842e6ef9","repo":"jlcodes99/cockpit-tools","slug":"ls-9aff84","errorCode":null,"errorMessage":"官方 LS 返回错误: {} - {} ({})","messagePattern":"官方 LS 返回错误: (.+?) - (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/modules/wakeup_gateway.rs","lineNumber":1121,"sourceCode":"        .header(\"x-codeium-csrf-token\", csrf_token)\n        .json(body)\n        .send()\n        .await\n        .map_err(|e| format!(\"官方 LS 请求失败: {} ({})\", e, path))?;\n\n    if !resp.status().is_success() {\n        let status = resp.status();\n        let text = resp.text().await.unwrap_or_default();\n        let preview: String = text.chars().take(512).collect();\n        crate::modules::logger::log_error(&format!(\n            \"[WakeupGateway] 官方 LS 返回错误: status={}, path={}, body_len={}, body={}\",\n            status,\n            path,\n            text.len(),\n            preview\n        ));\n        return Err(format!(\n            \"官方 LS 返回错误: {} - {} ({})\",\n            status, text, path\n        ));\n    }\n\n    resp.json::<Value>()\n        .await\n        .map_err(|e| format!(\"官方 LS 响应解析失败: {} ({})\", e, path))\n}\n\nenum OfficialLsExtensionAction {\n    Close(Vec<u8>),\n    HoldStream {\n        content_type: String,\n        first_message: Vec<u8>,\n        shutdown_notify: Arc<Notify>,\n    },\n}\n","sourceCodeStart":1103,"sourceCodeEnd":1139,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src-tauri/src/modules/wakeup_gateway.rs#L1103-L1139","documentation":"post_json_to_official_ls POSTs JSON to the official local Language Server (127.0.0.1 HTTPS with self-signed cert, CSRF header x-codeium-csrf-token). Any non-2xx HTTP status is converted into Err(format!(\"官方 LS 返回错误: {} - {} ({})\", status, text, path)) after logging a 512-char body preview. The message embeds the HTTP status code, the raw response body, and the request path so the caller can see exactly which LS RPC failed and why.","triggerScenarios":"Any post_json_to_official_ls call where the official LS responds with a non-success HTTP status: 400 on malformed request body, 401/403 on missing/invalid x-codeium-csrf-token or expired auth, 404 when the LS build does not expose the requested RPC path, 5xx on internal LS failure.","commonSituations":"Stale CSRF token after LS restart while the caller caches the old token; calling an RPC path that was renamed or removed in a newer/older official LS binary; LS overloaded or crashed mid-request returning 500; request JSON schema drift after an LS version change causing 400 Bad Request.","solutions":["Read the status and path in the message: 401/403 means re-fetch the CSRF token (and re-auth) from the current LS instance and retry.","400 with a body usually indicates request schema mismatch — compare the body against the LS version's expected schema and fix or drop the field.","404 means the path does not exist in this LS build — check the LS version and update the RPC path or gate the call on a version check.","500/502 points at the LS itself: check the LS process logs, restart it, and add a bounded retry with backoff for transient 5xx.","Log the full body (already previewed to 512 chars) when filing an issue; the body usually contains the LS's own error JSON explaining the rejection."],"exampleFix":"// before: single attempt, raw error surfaces\nlet v = post_json_to_official_ls(&client, &base, &csrf, path, &body).await?;\n// after: refresh CSRF + bounded retry on auth failure\nmatch post_json_to_official_ls(&client, &base, &csrf, path, &body).await {\n    Err(e) if e.contains(\" 401 \") || e.contains(\" 403 \") => {\n        let csrf = refresh_csrf_token(&base).await?;\n        post_json_to_official_ls(&client, &base, &csrf, path, &body).await\n    }\n    other => other,\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check: token present and LS reachable before the RPC\nif csrf_token.is_empty() {\n    return Err(\"missing x-codeium-csrf-token; refresh token first\".into());\n}\nlet ok = client.get(format!(\"{}\", base_url.trim_end_matches('/')))\n    .timeout(Duration::from_secs(3)).send().await\n    .map(|r| r.status().is_success()).unwrap_or(false);\nif !ok { return Err(\"official LS not reachable\".into()); }","typeGuard":null,"tryCatchPattern":"match post_json_to_official_ls(&client, &base, &csrf, path, &body).await {\n    Err(e) => {\n        // e = \"官方 LS 返回错误: <status> - <body> (<path>)\"\n        if e.starts_with(\"官方 LS 返回错误: 401\") || e.starts_with(\"官方 LS 返回错误: 403\") {\n            let fresh = refresh_csrf_token(&base).await?;\n            return post_json_to_official_ls(&client, &base, &fresh, path, &body).await;\n        }\n        if e.starts_with(\"官方 LS 返回错误: 5\") { /* bounded retry with backoff */ }\n        Err(e)\n    }\n    ok => ok,\n}","preventionTips":["Always send the current x-codeium-csrf-token; refresh it after any LS restart instead of caching across sessions.","Pin/gate calls on the official LS version and check that the RPC path still exists before invoking it.","Keep request JSON schemas in one module per LS RPC so version drift is caught by tests, not 400s in production.","Add bounded exponential-backoff retries for 5xx only; never blind-retry 4xx."],"tags":["http","http-status","network","language-server","rust","csrf"],"backgroundTag":"http-4xx-5xx-response","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"}