jlcodes99/cockpit-tools · warning

[WakeupGateway] 官方 LS SubscribeToUnifiedStateSyncTopic 解析失败:

Error message

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

What it means

For POSTs matching the SubscribeToUnifiedStateSyncTopic RPC, the local official-LS extension server parses the topic name out of the Connect request body via parse_subscribe_topic_from_connect_body. On failure it logs '官方 LS SubscribeToUnifiedStateSyncTopic 解析失败: {}' and returns HTTP 400 Bad Request, closing the stream. The parser must extract the topic string (e.g. uss-oauth) from the protobuf-encoded body, so the error means the body did not contain a decodable topic field.

Source

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

                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!(
                    "[WakeupGateway] 官方 LS SubscribeToUnifiedStateSyncTopic 解析失败: {}",
                    err
                ));
                return OfficialLsExtensionAction::Close(text_response(
                    400,
                    "Bad Request",
                    &err,
                    "text/plain; charset=utf-8",
                ));
            }
        };

        let topic_bytes = match topic.as_str() {
            "uss-oauth" => &state.uss_oauth_topic_bytes,
            "uss-enterprisePreferences" | "uss-agentPreferences" => &state.empty_topic_bytes,
            _ => &state.empty_topic_bytes,
        };
        let update = build_unified_state_sync_update_initial_state(topic_bytes);

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Log the raw body length and first bytes with the parse error to see whether an envelope was stripped or the body is empty.
  2. Update parse_subscribe_topic_from_connect_body to the field number/type used by the installed LS version's SubscribeRequest proto.
  3. Handle both unary (application/proto) and streaming (application/connect+proto) framing: decode the envelope before extracting the topic string field.
  4. Return 400 with the parser's message (already done) and skip serving that stream, so one bad subscription does not affect other RPCs on the server.
  5. If the sender is a legit LS build, diff its bundled .proto against the parser and fix the field mapping, then add a unit test with a captured request body.

Example fix

// before: single-shot parse, opaque failure
let topic = match parse_subscribe_topic_from_connect_body(&parsed.body) {
    Ok(v) => v,
    Err(err) => { log_error(&format!("... 解析失败: {}", err)); return Close(text_response(400, "Bad Request", &err, ...)); }
};
// after: strip connect envelope first and include body context in the log
let inner = strip_connect_envelope(&parsed.body, &content_type).unwrap_or(&parsed.body);
match parse_subscribe_topic_from_connect_body(inner) {
    Ok(v) => v,
    Err(err) => {
        log_error(&format!("SubscribeToUnifiedStateSyncTopic 解析失败: {} (len={})", err, inner.len()));
        return Close(text_response(400, "Bad Request", &err, "text/plain; charset=utf-8"));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate framing and presence before topic extraction
fn subscribable(body: &[u8], content_type: &str) -> bool {
    let ct = content_type.to_ascii_lowercase();
    (ct.starts_with("application/connect+proto") || ct.starts_with("application/proto")) && !body.is_empty()
}

Try / catch

// Handle per-request parse failure without killing the extension server
let topic = match parse_subscribe_topic_from_connect_body(&parsed.body) {
    Ok(v) => v,
    Err(err) => {
        log_error(&format!("SubscribeToUnifiedStateSyncTopic 解析失败: {}", err));
        return OfficialLsExtensionAction::Close(text_response(400, "Bad Request", &err, "text/plain; charset=utf-8"));
    }
};

Prevention

When it happens

Trigger: A client (official LS) subscribes to the unified state sync topic and parse_subscribe_topic_from_connect_body returns Err: the Connect body is empty, the protobuf field holding the topic string is missing or at an unexpected field number/wire type, the envelope framing was stripped incorrectly, or a proto schema change altered the subscription message layout.

Common situations: Official LS upgrade changes the SubscribeToUnifiedStateSyncTopic request proto so the topic field number shifts; client sends a streaming-framed body where the parser expects a single unary message (or vice versa); truncated body from a connection reset mid-request; another process probing the port with non-proto bytes.

Related errors


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