tonhowtf/omniget · error
X
Error message
X {}: {} What it means
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`.
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
Example fix
// before
client.gql_get("TweetDetail", json!({"id": id}), json!({}), None)?;
// after
client.gql_get("TweetDetail", json!({"focalTweetId": id, "withReactionsMetadata": false, "withReactionsPerspective": false}), json!({"article_pivot_enabled": true}), None)?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: validate variables before the call
if tweet_id.is_empty() || !tweet_id.chars().all(|c| c.is_ascii_digit()) {
return Err(anyhow!("invalid tweet id"));
} Try / catch
match client.gql_get(op, vars, feats, None).await {
Err(e) if e.to_string().starts_with("X ") => {
tracing::warn!("GraphQL rejected {}: {} — refresh ids/features and retry once", op, e);
client.refresh_ids().await?;
client.gql_get(op, vars, feats, None).await
}
r => r,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- operacao desconhecida
- X: HTTP
- Grok: nao consegui abrir uma conversa
- ERR_TOO_MANY_ATTACHMENTS
- HLS nao e suportado neste navegador
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/688da462e5aaa4bb.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/x/client.rs:337
));
}
let v: Value = serde_json::from_str(&text)
.map_err(|e| anyhow!("X {}: resposta invalida ({})", op, e))?;
if v.get("data")
.map(|d| d.is_null() || d.as_object().map(|o| o.is_empty()).unwrap_or(false))
.unwrap_or(true)
{
if let Some(msg) = v
.get("errors")
.and_then(|e| e.as_array())
.and_then(|a| a.first())
.and_then(|e| e.get("message"))
.and_then(|m| m.as_str())
{
if msg.contains("Query not found") || msg.contains("query_id") {
return Ok(Err("not_found".into()));
}
return Err(anyhow!("X {}: {}", op, msg));
}
}
Ok(Ok(v))
}
async fn refresh_ids(&self) -> anyhow::Result<()> {
super::query_ids::refresh(&self.http, self.cookie.as_deref())
.await
.map(|_| ())
}
pub async fn gql_get(
&self,
op: &str,
variables: Value,
extra_features: Value,
field_toggles: Option<Value>,
) -> anyhow::Result<Value> {View on GitHub (pinned to 8600b91f42)