{"record":{"id":"0673fb986da6d321","repo":"tonhowtf/omniget","slug":"x-rate-limit","errorCode":"X_RATE_LIMIT","errorMessage":"X_RATE_LIMIT:{}","messagePattern":"X_RATE_LIMIT:(.+?)","errorType":"error_code","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"src-tauri/omniget-core/src/core/tools/x/client.rs","lineNumber":304,"sourceCode":"        let path = format!(\"/i/api/graphql/{}/{}\", id, op);\n        if self.authed() {\n            (format!(\"https://x.com{}\", path), path)\n        } else {\n            (format!(\"https://api.x.com/graphql/{}/{}\", id, op), path)\n        }\n    }\n\n    async fn check(resp: reqwest::Response, op: &str) -> anyhow::Result<Result<Value, String>> {\n        let status = resp.status();\n        if status.as_u16() == 429 {\n            let reset = resp\n                .headers()\n                .get(\"x-rate-limit-reset\")\n                .and_then(|v| v.to_str().ok())\n                .and_then(|v| v.parse::<i64>().ok())\n                .map(|r| (r - chrono::Utc::now().timestamp()).max(1))\n                .unwrap_or(900);\n            return Err(anyhow!(\"X_RATE_LIMIT:{}\", reset));\n        }\n        let text = resp.text().await.unwrap_or_default();\n        if status.as_u16() == 404 {\n            return Ok(Err(\"not_found\".into()));\n        }\n        if status.as_u16() == 401 || status.as_u16() == 403 {\n            return Ok(Err(format!(\"auth:{}\", status.as_u16())));\n        }\n        if !status.is_success() {\n            return Err(anyhow!(\n                \"X {}: HTTP {} {}\",\n                op,\n                status,\n                text.chars().take(200).collect::<String>()\n            ));\n        }\n        let v: Value = serde_json::from_str(&text)\n            .map_err(|e| anyhow!(\"X {}: resposta invalida ({})\", op, e))?;","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/x/client.rs#L286-L322","documentation":"The X client's response check converts HTTP 429 into the sentinel error 'X_RATE_LIMIT:<seconds>' where <seconds> is derived from the x-rate-limit-reset header (fallback 900s). Callers are expected to parse the reset value and wait that long before retrying the GraphQL operation.","triggerScenarios":"Any gql request whose response carries status 429 — exceeding X's per-endpoint rate limits, especially when polling rapidly or sharing one account/IP across many requests.","commonSituations":"Tight retry loops hammering one GraphQL endpoint; batch jobs without backoff; multiple app instances behind the same IP consuming the shared limit.","solutions":["Parse the integer after 'X_RATE_LIMIT:' and schedule a retry after that many seconds.","Add exponential backoff with jitter and cache results to reduce request volume.","Spread requests across endpoints/accounts, and respect x-rate-limit-remaining headers proactively.","Stop polling loops that ignore prior 429s — they extend the lockout."],"exampleFix":"// before\nloop { match client.gql_get(op, &q).await { Ok(v) => break v, Err(_) => continue } }\n// after\nmatch client.gql_get(op, &q).await {\n    Ok(v) => v,\n    Err(e) if e.to_string().starts_with(\"X_RATE_LIMIT:\") => {\n        let reset: i64 = e.to_string().rsplit(':').next().unwrap().parse()?;\n        tokio::time::sleep(Duration::from_secs(reset as u64 + 1)).await;\n        client.gql_get(op, &q).await?\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// parse reset seconds and sleep before retrying\nif let Some(reset) = e.to_string().strip_prefix(\"X_RATE_LIMIT:\").and_then(|s| s.parse::<u64>().ok()) {\n    tokio::time::sleep(Duration::from_secs(reset + 1)).await;\n    return op().await; // one bounded retry\n}","preventionTips":["Implement global rate limiting/backoff in the X client wrapper, not per-callsite.","Cache GraphQL results to reduce duplicate requests.","Watch x-rate-limit-remaining and throttle proactively.","Never run unbounded retry loops against X endpoints."],"tags":["x-api","rate-limit","backoff","http-429"],"backgroundTag":"rate-limit-exceeded","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"}