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

  1. 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)
  2. For 5xx/rate-limit responses, wait and reconnect; the listen loop should be allowed to retry with backoff
  3. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/c1f13e7f2a17dcf0. Report an issue: GitHub.