zeroclaw-labs/zeroclaw · error
QQ gateway request failed ({status}): {err}
Error message
QQ gateway request failed ({status}): {err} What it means
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.
Source
Thrown at crates/zeroclaw-channels/src/qq.rs:546
let mut cache = self.token_cache.write().await;
*cache = Some((token.clone(), expiry));
}
Ok(token)
}
/// Get the WebSocket gateway URL.
async fn get_gateway_url(&self, token: &str) -> anyhow::Result<String> {
let resp = self
.http_client()
.get(format!("{QQ_API_BASE}/gateway"))
.header("Authorization", format!("QQBot {token}"))
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let err = resp.text().await.unwrap_or_default();
anyhow::bail!("QQ gateway request failed ({status}): {err}");
}
let data: serde_json::Value = resp.json().await?;
let url = data
.get("url")
.and_then(|u| u.as_str())
.ok_or_else(|| {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
.with_outcome(::zeroclaw_log::EventOutcome::Failure),
"Missing gateway URL in QQ response"
);
anyhow::Error::msg("Missing gateway URL in QQ response")
})?
.to_string();
Ok(url)View on GitHub (pinned to 88bb9c8533)
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
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight the same endpoint before starting the listener:
async fn qq_gateway_preflight() -> anyhow::Result<()> {
let resp = reqwest::get("https://api.sgroup.qq.com").await?;
anyhow::ensure!(resp.status().is_success() || resp.status().as_u16() >= 500, "QQ API unreachable: {}", resp.status());
Ok(())
} Try / catch
// Gateway fetch runs inside listen(); treat failures as reconnectable:
loop {
if let Err(e) = qq.listen().await {
if e.to_string().contains("QQ gateway request failed") {
tokio::time::sleep(backoff.next()).await; // reconnect with backoff
continue;
}
return Err(e);
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- QQ token request failed ({status}): {err}
- QQ WebSocket connection closed: invalid session (fresh auth
- QQ WebSocket connection closed: server requested reconnect (
- QQ WebSocket connection closed: close_code={code}, reason="{
- QQ WebSocket connection closed: stream ended unexpectedly
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/c1f13e7f2a17dcf0.
Report an issue: GitHub.