tonhowtf/omniget · error · anyhow::Error
token_expired
token_expired
Error message
token_expired
What it means
request_tweet maps HTTP 403 (Forbidden) and 429 (Too Many Requests) from Twitter's GraphQL endpoint to the error code `token_expired`. The guest token is treated as stale/rejected whenever Twitter refuses the request with these statuses, signaling the caller to refresh the token and retry.
Solutions
- Call get_guest_token to obtain and cache a fresh guest token, then retry request_tweet
- Distinguish 429 from 403 and add exponential backoff with Retry-After for 429 instead of only refreshing the token
- Reduce request frequency / add throttling and caching of tweet lookups
- Consider authenticated (OAuth) access if guest-token requests keep getting 403
Example fix
// before
if status == reqwest::StatusCode::FORBIDDEN || status == reqwest::StatusCode::TOO_MANY_REQUESTS {
return Err(anyhow!("token_expired"));
}
// after
match status {
reqwest::StatusCode::TOO_MANY_REQUESTS => Err(anyhow!("rate_limited")),
reqwest::StatusCode::FORBIDDEN => Err(anyhow!("token_expired")),
_ => Ok(())
} Defensive patterns
Strategy: retry
Try / catch
match request_tweet(id).await {
Err(e) if e.to_string() == "token_expired" => {
platform.refresh_guest_token().await?;
request_tweet(id).await
}
other => other,
} Prevention
- Refresh the guest token periodically instead of caching indefinitely
- Throttle tweet requests to stay under Twitter's rate limits
- Retry once with a fresh token before surfacing the error
- Treat repeated 403s as a signal Twitter changed guest-auth requirements
When it happens
Trigger: GET to the TweetResultByRestId GraphQL endpoint returns 403 (guest token rejected/expired or auth challenge) or 429 (rate limited). Both are collapsed into the same `token_expired` error even though 429 is actually rate limiting.
Common situations: Guest token cached for too long and Twitter invalidated it; bursts of downloads hitting Twitter's per-token rate limit (429); Twitter tightening bot protection so 403 is returned even for fresh tokens.
Related errors
- YouTube não retornou URL
- Falha ao obter guest token: HTTP
- Guest token ausente na resposta
- Twitch GQL não respondeu depois de 5 tentativas
- o servidor está limitando o acesso
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/828bfe0b3e10f6e1.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/platforms/twitter/mod.rs:364
.header("Accept-Language", "en")
.header("Content-Type", "application/json")
.header("Cookie", &cookie_val);
if has_auth_token {
request = request.header("x-twitter-auth-type", "OAuth2Session");
}
if let Some(ct0) = ct0 {
request = request.header("x-csrf-token", ct0);
}
let response = request.send().await?;
let status = response.status();
tracing::debug!("[twitter] graphql tweet_id={} status={}", tweet_id, status);
if status == reqwest::StatusCode::FORBIDDEN
|| status == reqwest::StatusCode::TOO_MANY_REQUESTS
{
return Err(anyhow!("token_expired"));
}
if status == reqwest::StatusCode::NOT_FOUND {
return Err(anyhow!("Post not available"));
}
if !status.is_success() {
return Err(anyhow!("Twitter API retornou HTTP {}", status));
}
response.json().await.map_err(Into::into)
}
fn calculate_syndication_token(id: &str) -> String {
let num: f64 = id.parse().unwrap_or(0.0);
let raw = (num / 1e15) * std::f64::consts::PI;
let base36 = Self::f64_to_base36(raw);
base36View on GitHub (pinned to 8600b91f42)