tonhowtf/omniget · error
Age-restricted content
Error message
Age-restricted content
What it means
Raised when the tweet result is a tombstone with reason "NsfwLoggedOut" or its tombstone text starts with "Age-restricted": the media is age-gated and the current (logged-out) session is not allowed to view it. The library deliberately blocks extraction here. It reflects X's sensitive-content policy for unauthenticated clients, not a parsing failure.
Solutions
- Use cookies from a logged-in, age-verified X account for sensitive media.
- Detect the NsfwLoggedOut reason up front and surface a clear 'age-restricted' message to end users.
- If legitimate, route the request through an authenticated extraction path rather than the guest GraphQL one.
- Treat this as a terminal condition — do not retry the same logged-out request.
Example fix
// before
if reason == "NsfwLoggedOut" || tombstone_text.starts_with("Age-restricted") {
return Err(anyhow!("Age-restricted content"));
}
// after
if reason == "NsfwLoggedOut" || tombstone_text.starts_with("Age-restricted") {
return Err(TwitterError::AgeRestricted { tweet_id });
} Defensive patterns
Strategy: try-catch
Validate before calling
// Detect age-gated tombstones before media extraction:
let reason = tweet_result.pointer("/result/reason").or_else(|| tweet_result.get("reason"))
.and_then(|v| v.as_str()).unwrap_or("");
let tombstone = tweet_result.pointer("/tombstone/text/text").and_then(|v| v.as_str()).unwrap_or("");
if reason == "NsfwLoggedOut" || tombstone.starts_with("Age-restricted") {
return Err(DisplayError::AgeRestricted);
} Type guard
fn is_age_restricted(tweet_result: &serde_json::Value) -> bool {
let reason = tweet_result.pointer("/result/reason")
.or_else(|| tweet_result.get("reason"))
.and_then(|v| v.as_str()).unwrap_or("");
let text = tweet_result.pointer("/tombstone/text/text")
.and_then(|v| v.as_str()).unwrap_or("");
reason == "NsfwLoggedOut" || text.starts_with("Age-restricted")
} Try / catch
match extractor.fetch(tweet_url) {
Err(e) if e.to_string() == "Age-restricted content" => {
ui.show("This media is age-restricted; sign in with an age-verified account.");
}
other => other?,
} Prevention
- Use cookies from a logged-in, age-verified X account when sensitive media is expected.
- Never retry a NsfwLoggedOut request with the same guest credentials.
- Inspect the reason/tombstone fields yourself to classify failures precisely.
- Warn users up front that sensitive media requires authenticated extraction.
When it happens
Trigger: extract_graphql_media encounters a tombstone whose reason is "NsfwLoggedOut" or whose /tombstone/text/text begins with "Age-restricted" — sensitive-media tweets fetched without an age-verified logged-in session.
Common situations: Scraping sensitive-media tweets with guest tokens only; X tightened logged-out access to NSFW content; region/age verification missing on the credentials used.
Related errors
- ERR_TOO_MANY_ATTACHMENTS
- nenhum favorito foi lido: esses perfis costumam exigir a…
- nenhum like foi lido: os likes só aparecem com a sessão do…
- o X serviu a versao deslogada da pagina
- não achei o token anti-CSRF do Goodreads; recapture os…
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/8a43528c41b34f69.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/twitter.rs:464
if reason == "Protected" {
return Err(anyhow!("Post privado"));
}
let tombstone_text = tweet_result
.pointer("/tombstone/text/text")
.and_then(|v| v.as_str())
.unwrap_or("");
tracing::warn!(
"[twitter] graphql tombstone tweet_id={} reason='{}' tombstone_text='{}'",
tweet_id,
reason,
tombstone_text
);
if reason == "NsfwLoggedOut" || tombstone_text.starts_with("Age-restricted") {
return Err(anyhow!("Age-restricted content"));
}
Err(anyhow!("Post not available"))
}
"Tweet" | "TweetWithVisibilityResults" => {
let media = Self::media_arrays_from_tweet_result(tweet_result)
.ok_or_else(|| anyhow!("No media found in tweet"))?;
tracing::debug!(
"[twitter] graphql extracted {} media entries for tweet_id={}",
media.len(),
tweet_id
);
Ok(media)
}
_ => Err(anyhow!("Post not available")),
}
}
View on GitHub (pinned to 8600b91f42)