{"record":{"id":"eabe53d78b10cbb6","repo":"tonhowtf/omniget","slug":"post-indisponivel-thread","errorCode":null,"errorMessage":"post indisponivel","messagePattern":"post indisponivel","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/x/thread.rs","lineNumber":95,"sourceCode":"            vars[\"cursor\"] = json!(c);\n        }\n        let v = client\n            .gql_get(\"TweetDetail\", vars, json!({}), Some(json!({\"withArticleRichContentState\": true, \"withArticlePlainText\": false, \"withGrokAnalyze\": false, \"withDisallowedReplyControls\": false})))\n            .await?;\n        all.extend(super::parse::tweets_from(&v));\n        // cursores de \"mostrar mais desta conversa\"\n        let next = find_show_more(&v);\n        if next.is_none() || Some(&next.clone().unwrap()) == cursor.as_ref() {\n            break;\n        }\n        cursor = next;\n    }\n    let all = super::dedup_posts(all);\n    let focal = all\n        .iter()\n        .find(|p| p.id == id)\n        .cloned()\n        .ok_or_else(|| anyhow!(\"post indisponivel\"))?;\n    let author = focal.author.handle.to_ascii_lowercase();\n    let mut by_id: std::collections::HashMap<String, XPost> = all\n        .iter()\n        .filter(|p| p.author.handle.to_ascii_lowercase() == author)\n        .map(|p| (p.id.clone(), p.clone()))\n        .collect();\n    // sobe ate a raiz\n    let mut root = focal.clone();\n    while let Some(parent) = root\n        .reply_to_id\n        .clone()\n        .and_then(|pid| by_id.get(&pid).cloned())\n    {\n        root = parent;\n    }\n    // desce pela cadeia de respostas do autor\n    let mut chain = vec![root.clone()];\n    by_id.remove(&root.id);","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/x/thread.rs#L77-L113","documentation":"unroll_graphql collects posts from an X (Twitter) GraphQL thread, deduplicates them, and then looks up the focal post by its ID. If the requested post ID is not present in the fetched thread data, it throws \"post indisponivel\". This means the thread was reachable but the specific post could not be located among its replies/ancestors.","triggerScenarios":"Calling unroll on an X thread whose GraphQL response does not contain a post matching the requested id — e.g. the tweet was deleted, the ID belongs to a different conversation, the API response was truncated, or the conversation module filtered it out.","commonSituations":"Deleted or protected tweets; URLs where the status ID is a redirect target that no longer exists; X changing GraphQL response shapes so thread entries are dropped during parsing; rate-limited/partial GraphQL responses.","solutions":["Verify the tweet ID extracted from the URL actually exists (open the URL in a browser) and retry with a fresh request.","Check if the tweet is deleted, protected, or age-restricted; use an authenticated session if available.","Inspect the raw GraphQL response to see whether parsing dropped entries (response-shape change) and update the parser.","Retry on transient failures — a partial GraphQL response can omit the focal post."],"exampleFix":"// before\nlet focal = all.iter().find(|p| p.id == id).cloned().ok_or_else(|| anyhow!(\"post indisponivel\"))?;\n// after\nlet focal = match all.iter().find(|p| p.id == id) {\n    Some(p) => p.clone(),\n    None => return Err(anyhow!(\"post {} indisponivel (thread continha {} posts)\", id, all.len())),\n};","handlingStrategy":"try-catch","validationCode":"// Rust\nif tweet_id.is_empty() || !tweet_id.chars().all(|c| c.is_ascii_digit()) {\n    return Err(anyhow!(\"ID de tweet inválido antes de unroll\"));\n}","typeGuard":"fn has_focal_post(all: &[XPost], id: &str) -> bool {\n    all.iter().any(|p| p.id == id)\n}","tryCatchPattern":"match unroll(url).await {\n    Ok(thread) => use(thread),\n    Err(e) if e.to_string().contains(\"post indisponivel\") => {\n        eprintln!(\"post removido ou thread parcial; verifique a URL no navegador\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Validate the status ID is numeric before calling unroll","Open the tweet URL in a browser to confirm it still exists","Retry once on failure — partial GraphQL responses are transient","Log all.len() on failure to distinguish empty threads from shape changes"],"tags":["twitter","graphql","resource-not-found"],"backgroundTag":"entity-not-found","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"}