tonhowtf/omniget · error

Twitch GQL não respondeu depois de 5 tentativas: {}

Error message

Twitch GQL não respondeu depois de 5 tentativas: {}

What it means

This error is raised after the Twitch GQL client exhausts its 5 retry attempts without receiving a successful response. On each attempt the client records the last failure reason (429 rate limit or server error) in `last`; when the loop ends it bails with that reason embedded. It means Twitch remained unavailable or rate-limited across all retries — a persistent transient failure, not a single bad request.

Solutions

  1. Add exponential backoff with jitter between retry attempts instead of retrying immediately.
  2. Inspect `last` in the message: if HTTP 429, slow down call rate, cache results, and respect Twitch rate limits.
  3. Route requests through a different IP/proxy if the current IP is persistently throttled.
  4. Increase the attempt count and/or add a longer cool-down for server errors (5xx) during Twitch outages.
  5. Surface the error to the caller with the recorded `last` status so users know it was a rate limit vs server error.

Example fix

// before
for _ in 0..5 {
    // attempt request, on 429/5xx: last = ...; continue;
}
bail!("Twitch GQL não respondeu depois de 5 tentativas: {}", last)
// after
for attempt in 0..5 {
    // attempt request...
    tokio::time::sleep(Duration::from_millis(500 * 2u64.pow(attempt))).await;
}
bail!("Twitch GQL não respondeu depois de 5 tentativas: {}", last)
Defensive patterns

Strategy: retry

Try / catch

match gql.query(&q).await {
    Ok(v) => Ok(v),
    Err(e) if e.to_string().contains("não respondeu depois de 5 tentativas") => {
        tokio::time::sleep(Duration::from_secs(60)).await; // cool-down, then retry
        gql.query(&q).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Any call through post (query or persisted query) where all 5 attempts return HTTP 429 or a 5xx status, so the retry loop never reaches the success path.

Common situations: Hammering Twitch's GQL endpoint without backoff and hitting sustained rate limits; Twitch GQL outage or maintenance window; IP-level throttling (datacenter/VPN IPs are heavily limited); misconfigured retry interval too short for the rate-limit window to reset.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/19515f62f3d2ca4c. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/twitch/gql.rs:169

                .await;
            let resp = match sent {
                Ok(r) => r,
                Err(e) => {
                    last = e.to_string();
                    continue;
                }
            };
            let status = resp.status();
            if status.as_u16() == 429 || status.is_server_error() {
                last = format!("HTTP {}", status);
                continue;
            }
            if !status.is_success() {
                bail!("Twitch GQL respondeu HTTP {}", status);
            }
            return Ok(resp.json::<Value>().await?);
        }
        bail!("Twitch GQL não respondeu depois de 5 tentativas: {}", last)
    }

    /// Query anônima em texto (as públicas aceitam sem persisted query).
    pub async fn query(&self, query: &str) -> anyhow::Result<Value> {
        let body = json!({ "query": query });
        let json = self.post(&body).await?;
        if let Some(msg) = first_error(&json) {
            bail!("Twitch GQL: {}", msg);
        }
        json.get("data")
            .cloned()
            .ok_or_else(|| anyhow!("resposta do Twitch GQL sem `data`"))
    }

    /// Persisted query (formato em lote, como o site manda). Devolve o
    /// primeiro elemento cru, para quem quiser ler `errors` também.
    pub async fn persisted(&self, op: &str, hash: &str, vars: Value) -> anyhow::Result<Value> {
        let body = json!([{

View on GitHub (pinned to 8600b91f42)