jlcodes99/cockpit-tools · warning

[WakeupGateway] 官方 LS LanguageServerStarted 解析失败: {}

Error message

[WakeupGateway] 官方 LS LanguageServerStarted 解析失败: {}

What it means

The gateway module implements a local mock of the official LS's Connect RPC surface. When an incoming POST matches the LanguageServerStarted RPC method, route_official_ls_extension_request calls parse_official_ls_started_request on the request body; if protobuf parsing fails it logs '官方 LS LanguageServerStarted 解析失败: {}' and returns HTTP 400 Bad Request with the parse error. This happens because the incoming Connect/proto envelope did not decode into the expected LanguageServerStarted message.

Source

Thrown at src-tauri/src/modules/wakeup_gateway.rs:1252

            "text/plain; charset=utf-8",
        ));
    }

    if path_matches_rpc_method(&path, "LanguageServerStarted") {
        match parse_official_ls_started_request(&parsed.body) {
            Ok(started) => {
                if let Ok(mut guard) = state.started_sender.lock() {
                    if let Some(tx) = guard.take() {
                        let _ = tx.send(started);
                    }
                }
                return OfficialLsExtensionAction::Close(extension_unary_response(
                    &content_type,
                    &[],
                ));
            }
            Err(err) => {
                crate::modules::logger::log_error(&format!(
                    "[WakeupGateway] 官方 LS LanguageServerStarted 解析失败: {}",
                    err
                ));
                return OfficialLsExtensionAction::Close(text_response(
                    400,
                    "Bad Request",
                    &err,
                    "text/plain; charset=utf-8",
                ));
            }
        }
    }

    if path_matches_rpc_method(&path, "SubscribeToUnifiedStateSyncTopic") {
        let topic = match parse_subscribe_topic_from_connect_body(&parsed.body) {
            Ok(v) => v,
            Err(err) => {
                crate::modules::logger::log_error(&format!(

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Log and inspect the raw request bytes and content-type header alongside the parse error to confirm whether the body is protobuf at all.
  2. Update parse_official_ls_started_request to match the proto schema of the installed official LS version (compare against the LS's bundled .proto definitions).
  3. Reject unsupported content-types early with a clear 415-style response instead of attempting protobuf decode on JSON or form bodies.
  4. Verify the Connect envelope framing: for application/connect+proto the body is length-prefixed messages; strip the envelope before decoding the inner message.
  5. Capture the offending payload (bounded hex/log dump) for a bug report if the sender is a legitimate LS build.

Example fix

// before: parse regardless of content-type
match parse_official_ls_started_request(&parsed.body) { ... }
// after: guard content-type and log offending bytes on failure
if !content_type.contains("proto") {
    return Close(text_response(415, "Unsupported Media Type", "expected application/proto", "text/plain; charset=utf-8"));
}
match parse_official_ls_started_request(&parsed.body) {
    Ok(started) => ...,
    Err(err) => {
        log_error(&format!("LanguageServerStarted 解析失败: {} (len={}, head={:?})", err, parsed.body.len(), &parsed.body[..parsed.body.len().min(32)]));
        Close(text_response(400, "Bad Request", &err, "text/plain; charset=utf-8"))
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate before parsing: content-type and non-empty protobuf-ish body
fn plausibly_proto(body: &[u8], content_type: &str) -> bool {
    content_type.to_ascii_lowercase().contains("proto") && !body.is_empty()
}

Try / catch

// Server-side: never panic on bad input; respond 400 and keep serving
match parse_official_ls_started_request(&parsed.body) {
    Ok(started) => { /* forward to started_sender */ }
    Err(err) => {
        log_error(&format!("LanguageServerStarted 解析失败: {}", err));
        return OfficialLsExtensionAction::Close(text_response(400, "Bad Request", &err, "text/plain; charset=utf-8"));
    }
}

Prevention

When it happens

Trigger: An official LS (or any client) POSTs to the local extension server's LanguageServerStarted endpoint and parse_official_ls_started_request returns Err: malformed or truncated protobuf body, wrong Connect envelope framing (unary vs streaming content-type), empty body, or a proto schema version whose field layout no longer matches the parser.

Common situations: Official LS version upgrade changed the LanguageServerStarted proto definition; a client sends application/json where application/proto is expected (or vice versa) so the bytes are not valid protobuf; proxy or middleware corrupts/truncates the request body; a security scanner or wrong client hits the local port with garbage bytes.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/51648ac44da122c7. Report an issue: GitHub.