tonhowtf/omniget · warning · anyhow::Error
Post privado
Error message
Post privado
What it means
extract_graphql_media raises `Post privado` (private post) when the tweet result's `reason` field equals `Protected`. Twitter explicitly marks the tweet as protected, meaning the account is private and the media cannot be fetched without authenticated, authorized access.
Solutions
- Detect `reason: Protected` early and return a clear user-facing error distinguishing it from deleted posts
- Inform the user the account is private and media cannot be downloaded without logging in with an authorized account
- Add authenticated-access support (session cookies) if private-post access is a requirement
- Skip protected tweets gracefully in batch downloads instead of failing the whole job
Example fix
// before
if reason == "Protected" {
return Err(anyhow!("Post privado"));
}
// after
if reason == "Protected" {
return Err(PlatformError::PrivatePost(format!("tweet {} é de uma conta privada", tweet_id)));
} Defensive patterns
Strategy: try-catch
Validate before calling
fn reason_is_protected(json: &serde_json::Value) -> bool {
json.pointer("/data/threaded_conversation_with_injections_v2/instructions").and_then(|i| i.as_array()).map(|ins| ins.iter().filter_map(|i| i.get("entries")).flat_map(|e| e.as_array().unwrap_or(&vec![]).iter()).any(|e| e.pointer("/content/itemContent/tweet_results/result/reason").and_then(|r| r.as_str()) == Some("Protected"))).unwrap_or(false)).unwrap_or(false)
} Type guard
fn is_protected_result(result: &serde_json::Value) -> bool {
result.pointer("/result/reason").or_else(|| result.get("reason")).and_then(|r| r.as_str()) == Some("Protected")
} Try / catch
match extract_graphql_media(&json, id) {
Err(e) if e.to_string() == "Post privado" => {
ui.notify_private_post(id); // distinct UX from deleted/unavailable
Err(SkipPost)
}
other => other,
} Prevention
- Distinguish Protected from tombstone/deleted reasons in error handling
- Pre-check account visibility when the tweet URL includes a known-protected handle
- Offer authenticated-session support if private media access is required
- Skip protected posts gracefully in batch jobs instead of aborting
When it happens
Trigger: GraphQL tweet result contains tweet_results/result with `reason: "Protected"` — the tweet belongs to a protected (private) account and the guest session has no access.
Common situations: User pastes a link to a tweet from a private account; account was switched to protected after the tweet was posted; user expects public content but the author locked their account.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- ERR_TOO_MANY_ATTACHMENTS
- HLS nao e suportado neste navegador
- refresh returned no audio format
- post indisponivel
- Twitter API retornou HTTP
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/17ea2123d8d41540.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/platforms/twitter/mod.rs:514
.get("__typename")
.and_then(|v| v.as_str())
.unwrap_or("");
tracing::debug!(
"[twitter] graphql media typename={} tweet_id={}",
typename,
tweet_id
);
match typename {
"TweetUnavailable" | "TweetTombstone" => {
let reason = tweet_result
.pointer("/result/reason")
.or_else(|| tweet_result.get("reason"))
.and_then(|v| v.as_str())
.unwrap_or("");
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"));
}
View on GitHub (pinned to 8600b91f42)