{"record":{"id":"c1f13e7f2a17dcf0","repo":"zeroclaw-labs/zeroclaw","slug":"qq-gateway-request-failed-status-err","errorCode":null,"errorMessage":"QQ gateway request failed ({status}): {err}","messagePattern":"QQ gateway request failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/qq.rs","lineNumber":546,"sourceCode":"            let mut cache = self.token_cache.write().await;\n            *cache = Some((token.clone(), expiry));\n        }\n        Ok(token)\n    }\n\n    /// Get the WebSocket gateway URL.\n    async fn get_gateway_url(&self, token: &str) -> anyhow::Result<String> {\n        let resp = self\n            .http_client()\n            .get(format!(\"{QQ_API_BASE}/gateway\"))\n            .header(\"Authorization\", format!(\"QQBot {token}\"))\n            .send()\n            .await?;\n\n        if !resp.status().is_success() {\n            let status = resp.status();\n            let err = resp.text().await.unwrap_or_default();\n            anyhow::bail!(\"QQ gateway request failed ({status}): {err}\");\n        }\n\n        let data: serde_json::Value = resp.json().await?;\n        let url = data\n            .get(\"url\")\n            .and_then(|u| u.as_str())\n            .ok_or_else(|| {\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure),\n                    \"Missing gateway URL in QQ response\"\n                );\n                anyhow::Error::msg(\"Missing gateway URL in QQ response\")\n            })?\n            .to_string();\n\n        Ok(url)","sourceCodeStart":528,"sourceCodeEnd":564,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/qq.rs#L528-L564","documentation":"Before connecting its WebSocket, the QQ channel calls the open API to fetch the gateway URL; get_gateway_url bails with status and body when that request returns non-2xx. This call is authenticated with the app access token, so the usual causes are an invalid/expired token or the QQ API rejecting the app, with network failures surfacing through reqwest instead.","triggerScenarios":"listen() starting after the cached access token expired or was revoked; QQ API outage or rate limiting on the gateway endpoint; invalid app credentials that only surface at this stage.","commonSituations":"Long-running processes whose token refresh failed earlier; QQ platform incidents; restricted egress environments half-blocking api.sgroup.qq.com; restarts right after credential changes.","solutions":["Check the status/body: 401/403 style responses mean token/app problems — verify app_id/app_secret and let the channel re-auth (restart it)","For 5xx/rate-limit responses, wait and reconnect; the listen loop should be allowed to retry with backoff","Verify network reachability of https://api.sgroup.qq.com and any channel.qq proxy_url configuration"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight the same endpoint before starting the listener:\nasync fn qq_gateway_preflight() -> anyhow::Result<()> {\n    let resp = reqwest::get(\"https://api.sgroup.qq.com\").await?;\n    anyhow::ensure!(resp.status().is_success() || resp.status().as_u16() >= 500, \"QQ API unreachable: {}\", resp.status());\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// Gateway fetch runs inside listen(); treat failures as reconnectable:\nloop {\n    if let Err(e) = qq.listen().await {\n        if e.to_string().contains(\"QQ gateway request failed\") {\n            tokio::time::sleep(backoff.next()).await;  // reconnect with backoff\n            continue;\n        }\n        return Err(e);\n    }\n}","preventionTips":["Let the listen loop reconnect with exponential backoff instead of crashing the daemon","Treat 401-style gateway failures as a signal to re-auth (restart channel) rather than a network problem","Watch QQ open-platform status pages during incidents before debugging locally"],"tags":["qq","websocket","gateway","authentication","network"],"backgroundTag":"websocket-gateway-unavailable","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}