{"record":{"id":"17ea2123d8d41540","repo":"tonhowtf/omniget","slug":"post-privado-mod","errorCode":null,"errorMessage":"Post privado","messagePattern":"Post privado","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"src-tauri/src/platforms/twitter/mod.rs","lineNumber":514,"sourceCode":"            .get(\"__typename\")\n            .and_then(|v| v.as_str())\n            .unwrap_or(\"\");\n        tracing::debug!(\n            \"[twitter] graphql media typename={} tweet_id={}\",\n            typename,\n            tweet_id\n        );\n\n        match typename {\n            \"TweetUnavailable\" | \"TweetTombstone\" => {\n                let reason = tweet_result\n                    .pointer(\"/result/reason\")\n                    .or_else(|| tweet_result.get(\"reason\"))\n                    .and_then(|v| v.as_str())\n                    .unwrap_or(\"\");\n\n                if reason == \"Protected\" {\n                    return Err(anyhow!(\"Post privado\"));\n                }\n\n                let tombstone_text = tweet_result\n                    .pointer(\"/tombstone/text/text\")\n                    .and_then(|v| v.as_str())\n                    .unwrap_or(\"\");\n\n                tracing::warn!(\n                    \"[twitter] graphql tombstone tweet_id={} reason='{}' tombstone_text='{}'\",\n                    tweet_id,\n                    reason,\n                    tombstone_text\n                );\n\n                if reason == \"NsfwLoggedOut\" || tombstone_text.starts_with(\"Age-restricted\") {\n                    return Err(anyhow!(\"Age-restricted content\"));\n                }\n","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/twitter/mod.rs#L496-L532","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif reason == \"Protected\" {\n    return Err(anyhow!(\"Post privado\"));\n}\n// after\nif reason == \"Protected\" {\n    return Err(PlatformError::PrivatePost(format!(\"tweet {} é de uma conta privada\", tweet_id)));\n}","handlingStrategy":"try-catch","validationCode":"fn reason_is_protected(json: &serde_json::Value) -> bool {\n    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)\n}","typeGuard":"fn is_protected_result(result: &serde_json::Value) -> bool {\n    result.pointer(\"/result/reason\").or_else(|| result.get(\"reason\")).and_then(|r| r.as_str()) == Some(\"Protected\")\n}","tryCatchPattern":"match extract_graphql_media(&json, id) {\n    Err(e) if e.to_string() == \"Post privado\" => {\n        ui.notify_private_post(id); // distinct UX from deleted/unavailable\n        Err(SkipPost)\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["twitter","graphql","private-account","authorization"],"backgroundTag":"permission-denied","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"}