tonhowtf/omniget · error

Twitch GQL retornou HTTP

Error message

Twitch GQL retornou HTTP {}

What it means

Raised by fetch_clip_metadata when the POST to https://gql.twitch.tv/gql returns a non-2xx HTTP status. The error embeds the status code, so it covers 4xx (bad client-id, malformed query) and 5xx (Twitch outage) cases.

Solutions

  1. Log/inspect response.status() and the response body to identify 4xx vs 5xx
  2. Retry with backoff on 429/5xx
  3. Update the CLIENT_ID constant to the current public web client-id
  4. Verify proxy/TLS configuration if 403s appear

Example fix

// before
if !response.status().is_success() {
    return Err(anyhow!("Twitch GQL retornou HTTP {}", response.status()));
}
// after
if response.status() == reqwest::StatusCode::TOO_MANY_REQUESTS {
    tokio::time::sleep(Duration::from_secs(5)).await;
    return self.fetch_clip_metadata(slug).await; // bounded retry
}
if !response.status().is_success() {
    let body = response.text().await.unwrap_or_default();
    return Err(anyhow!("Twitch GQL retornou HTTP {}: {}", body.len(), body));
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: probe GQL availability
let status = reqwest::Client::new().post("https://gql.twitch.tv/gql")
    .header("client-id", "kimne78kx3ncx6brgo4mv6wki5h1ko")
    .json(&serde_json::json!({"query":"{clip(slug:\"x\"){id}}"}))
    .send().await?.status();

Try / catch

for attempt in 0..3 {
    match downloader.get_media_info(url).await {
        Err(e) if e.to_string().contains("Twitch GQL retornou HTTP 429")
              || e.to_string().contains("HTTP 5") => tokio::time::sleep(Duration::from_secs(2u64 << attempt)).await,
        other => return other,
    }
}

Prevention

When it happens

Trigger: Any failed GraphQL metadata request: network path returns 400/401 for an invalid client-id header or malformed query, 403 for blocked clients, 429 rate limiting, or 5xx during Twitch incidents.

Common situations: Twitch rotated/invalidated the hardcoded CLIENT_ID; rate-limited by excessive polling; corporate proxy intercepting requests; Twitch GQL outage.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/platforms/twitch.rs:139

    async fn fetch_clip_metadata(&self, slug: &str) -> anyhow::Result<ClipMetadata> {
        let query = format!(
            r#"{{ clip(slug: "{}") {{ broadcaster {{ login }} curator {{ login }} durationSeconds id medium: thumbnailURL(width: 480, height: 272) title videoQualities {{ quality sourceURL }} }} }}"#,
            slug
        );

        let body = serde_json::json!({ "query": query });

        let response = self
            .client
            .post(GQL_URL)
            .header("client-id", CLIENT_ID)
            .json(&body)
            .send()
            .await?;

        if !response.status().is_success() {
            return Err(anyhow!("Twitch GQL retornou HTTP {}", response.status()));
        }

        let json: serde_json::Value = response.json().await?;

        let clip = json
            .pointer("/data/clip")
            .ok_or_else(|| anyhow!("Clip not found: {}", slug))?;

        if clip.is_null() {
            return Err(anyhow!("Clip not found: {}", slug));
        }

        let title = clip
            .get("title")
            .and_then(|v| v.as_str())
            .unwrap_or("Untitled")
            .to_string();

View on GitHub (pinned to 8600b91f42)