{"record":{"id":"9508855a8d8cfd09","repo":"tonhowtf/omniget","slug":"twitch-gql-retornou-http","errorCode":null,"errorMessage":"Twitch GQL retornou HTTP {}","messagePattern":"Twitch GQL retornou HTTP (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/twitch.rs","lineNumber":139,"sourceCode":"\n    async fn fetch_clip_metadata(&self, slug: &str) -> anyhow::Result<ClipMetadata> {\n        let query = format!(\n            r#\"{{ clip(slug: \"{}\") {{ broadcaster {{ login }} curator {{ login }} durationSeconds id medium: thumbnailURL(width: 480, height: 272) title videoQualities {{ quality sourceURL }} }} }}\"#,\n            slug\n        );\n\n        let body = serde_json::json!({ \"query\": query });\n\n        let response = self\n            .client\n            .post(GQL_URL)\n            .header(\"client-id\", CLIENT_ID)\n            .json(&body)\n            .send()\n            .await?;\n\n        if !response.status().is_success() {\n            return Err(anyhow!(\"Twitch GQL retornou HTTP {}\", response.status()));\n        }\n\n        let json: serde_json::Value = response.json().await?;\n\n        let clip = json\n            .pointer(\"/data/clip\")\n            .ok_or_else(|| anyhow!(\"Clip not found: {}\", slug))?;\n\n        if clip.is_null() {\n            return Err(anyhow!(\"Clip not found: {}\", slug));\n        }\n\n        let title = clip\n            .get(\"title\")\n            .and_then(|v| v.as_str())\n            .unwrap_or(\"Untitled\")\n            .to_string();\n","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/twitch.rs#L121-L157","documentation":"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.","triggerScenarios":"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.","commonSituations":"Twitch rotated/invalidated the hardcoded CLIENT_ID; rate-limited by excessive polling; corporate proxy intercepting requests; Twitch GQL outage.","solutions":["Log/inspect response.status() and the response body to identify 4xx vs 5xx","Retry with backoff on 429/5xx","Update the CLIENT_ID constant to the current public web client-id","Verify proxy/TLS configuration if 403s appear"],"exampleFix":"// before\nif !response.status().is_success() {\n    return Err(anyhow!(\"Twitch GQL retornou HTTP {}\", response.status()));\n}\n// after\nif response.status() == reqwest::StatusCode::TOO_MANY_REQUESTS {\n    tokio::time::sleep(Duration::from_secs(5)).await;\n    return self.fetch_clip_metadata(slug).await; // bounded retry\n}\nif !response.status().is_success() {\n    let body = response.text().await.unwrap_or_default();\n    return Err(anyhow!(\"Twitch GQL retornou HTTP {}: {}\", body.len(), body));\n}","handlingStrategy":"retry","validationCode":"// Pre-flight: probe GQL availability\nlet status = reqwest::Client::new().post(\"https://gql.twitch.tv/gql\")\n    .header(\"client-id\", \"kimne78kx3ncx6brgo4mv6wki5h1ko\")\n    .json(&serde_json::json!({\"query\":\"{clip(slug:\\\"x\\\"){id}}\"}))\n    .send().await?.status();","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match downloader.get_media_info(url).await {\n        Err(e) if e.to_string().contains(\"Twitch GQL retornou HTTP 429\")\n              || e.to_string().contains(\"HTTP 5\") => tokio::time::sleep(Duration::from_secs(2u64 << attempt)).await,\n        other => return other,\n    }\n}","preventionTips":["Back off on 429/5xx with exponential delay","Keep CLIENT_ID current with Twitch's public web client-id","Avoid tight polling loops against GQL","Check https://status.twitch.tv during suspected outages"],"tags":["rust","twitch","http","api"],"backgroundTag":"http-error-response","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}