{"record":{"id":"688da462e5aaa4bb","repo":"tonhowtf/omniget","slug":"x","errorCode":null,"errorMessage":"X {}: {}","messagePattern":"X \\{\\}: \\{\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/x/client.rs","lineNumber":337,"sourceCode":"            ));\n        }\n        let v: Value = serde_json::from_str(&text)\n            .map_err(|e| anyhow!(\"X {}: resposta invalida ({})\", op, e))?;\n        if v.get(\"data\")\n            .map(|d| d.is_null() || d.as_object().map(|o| o.is_empty()).unwrap_or(false))\n            .unwrap_or(true)\n        {\n            if let Some(msg) = v\n                .get(\"errors\")\n                .and_then(|e| e.as_array())\n                .and_then(|a| a.first())\n                .and_then(|e| e.get(\"message\"))\n                .and_then(|m| m.as_str())\n            {\n                if msg.contains(\"Query not found\") || msg.contains(\"query_id\") {\n                    return Ok(Err(\"not_found\".into()));\n                }\n                return Err(anyhow!(\"X {}: {}\", op, msg));\n            }\n        }\n        Ok(Ok(v))\n    }\n\n    async fn refresh_ids(&self) -> anyhow::Result<()> {\n        super::query_ids::refresh(&self.http, self.cookie.as_deref())\n            .await\n            .map(|_| ())\n    }\n\n    pub async fn gql_get(\n        &self,\n        op: &str,\n        variables: Value,\n        extra_features: Value,\n        field_toggles: Option<Value>,\n    ) -> anyhow::Result<Value> {","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/x/client.rs#L319-L355","documentation":"The X (Twitter) GraphQL endpoint returned HTTP 200 with an empty/null `data` field and an `errors` array whose first message is not a known recoverable case (not \"Query not found\"/query_id, not 404/401/403 already handled). The client surfaces the raw GraphQL error message prefixed with the operation name, e.g. `X UserByScreenName: Field ... is required`.","triggerScenarios":"Calling gql_get/gql_post/rest_post_form when X rejects the request at the GraphQL layer: missing or invalid required variables, unsupported/disabled feature flags, invalid fieldToggles, or a suspended/private target returning errors in a 200 body.","commonSituations":"X changed the GraphQL schema (renamed/removed a field or feature flag), the caller passes malformed variables (wrong tweet/user id format), or an operation's hardcoded features map is stale after a X rollout.","solutions":["Read the operation name and message in the error, then fix the variables/features payload for that op to match X's current schema","Refresh query ids and features (clear cached query_ids so a fresh manifest is fetched)","Verify the target resource exists and is accessible with the current session (some ops fail for private/suspended accounts)","Log the full response body (check truncates it); reproduce with curl using the same cookies/csrf to confirm the schema mismatch","Update omniget-core's per-op feature flags to the current values scraped from x.com"],"exampleFix":"// before\nclient.gql_get(\"TweetDetail\", json!({\"id\": id}), json!({}), None)?;\n// after\nclient.gql_get(\"TweetDetail\", json!({\"focalTweetId\": id, \"withReactionsMetadata\": false, \"withReactionsPerspective\": false}), json!({\"article_pivot_enabled\": true}), None)?;","handlingStrategy":"try-catch","validationCode":"// Rust: validate variables before the call\nif tweet_id.is_empty() || !tweet_id.chars().all(|c| c.is_ascii_digit()) {\n    return Err(anyhow!(\"invalid tweet id\"));\n}","typeGuard":null,"tryCatchPattern":"match client.gql_get(op, vars, feats, None).await {\n    Err(e) if e.to_string().starts_with(\"X \") => {\n        tracing::warn!(\"GraphQL rejected {}: {} — refresh ids/features and retry once\", op, e);\n        client.refresh_ids().await?;\n        client.gql_get(op, vars, feats, None).await\n    }\n    r => r,\n}","preventionTips":["Keep the per-op feature flags in sync with x.com by refreshing query ids regularly","Validate id formats (numeric user/tweet ids) before issuing GraphQL calls","Log full response bodies on failure to see the raw GraphQL errors[] message","Pin and re-verify payloads after any X schema change announcement"],"tags":["x","graphql","api-error"],"backgroundTag":"api-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"}