{"record":{"id":"4820bbf3af9e3b32","repo":"tonhowtf/omniget","slug":"resposta-inesperada-do-reddit-n-o-a-lista-de-dois-listings","errorCode":null,"errorMessage":"resposta inesperada do Reddit (não é a lista de dois listings)","messagePattern":"resposta inesperada do Reddit \\(não é a lista de dois listings\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/reddit/thread.rs","lineNumber":193,"sourceCode":"                    .unwrap_or_default();\n                let parent_id = s(data, \"parent_id\");\n                if !parent_id.is_empty() {\n                    mores.push(MoreRef {\n                        parent_id,\n                        children,\n                    });\n                }\n            }\n            _ => {}\n        }\n    }\n}\n\n/// A resposta de um permalink é `[listing do post, listing dos comentários]`.\npub fn parse_thread_json(root: &Value) -> Result<(Post, Vec<Comment>, Vec<MoreRef>)> {\n    let arr = root\n        .as_array()\n        .ok_or_else(|| anyhow!(\"resposta inesperada do Reddit (não é a lista de dois listings)\"))?;\n    let post_data = arr\n        .first()\n        .and_then(|l| l.pointer(\"/data/children/0/data\"))\n        .ok_or_else(|| anyhow!(\"o post não veio na resposta (removido, privado ou apagado?)\"))?;\n    let post = parse_post(post_data);\n    let mut flat = Vec::new();\n    let mut mores = Vec::new();\n    if let Some(children) = arr.get(1).and_then(|l| l.pointer(\"/data/children\")) {\n        parse_things(children, &mut flat, &mut mores);\n    }\n    Ok((post, flat, mores))\n}\n\n/// O `things` de `api/morechildren.json`.\npub fn parse_more_json(root: &Value) -> (Vec<Comment>, Vec<MoreRef>) {\n    let mut flat = Vec::new();\n    let mut mores = Vec::new();\n    if let Some(things) = root","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/reddit/thread.rs#L175-L211","documentation":"`parse_thread_json` expects Reddit's permalink response to be a JSON array of exactly two listings (post listing, then comments listing). This error is thrown when the root JSON value is not an array at all — meaning the response body did not have the documented shape.","triggerScenarios":"Calling parse_thread_json (via expand, run, thread_from_fixture, or separa_os_dois_tipos_de_more) with a root Value that is an object, string, or null instead of the `[post, comments]` array — e.g. Reddit returned an HTML error page parsed loosely, an error JSON object, or a malformed fixture.","commonSituations":"Reddit serving an interstitial/error JSON (e.g. blocked message) instead of thread data; passing the wrong file to thread_from_fixture; Reddit API shape changes; HTML login/blocked pages being fed to the parser.","solutions":["Log/inspect the raw response body before parsing to confirm it is the expected `[listing, listing]` array","Check whether the request was redirected to a blocked/login page and handle that case before parsing","Validate the response with a shape check (root.is_array() && root.len() >= 2) before calling parse_thread_json","Update the parser if Reddit changed its permalink response structure"],"exampleFix":"// before\nlet (post, comments, mores) = parse_thread_json(&root)?;\n// after\nif !root.is_array() || root.as_array().map_or(true, |a| a.len() < 2) {\n    anyhow::bail!(\"corpo inesperado: {}\", serde_json::to_string(&root).unwrap_or_default());\n}\nlet (post, comments, mores) = parse_thread_json(&root)?;","handlingStrategy":"type-guard","validationCode":"fn looks_like_thread_json(root: &serde_json::Value) -> bool {\n    root.as_array().map_or(false, |a| a.len() >= 2)\n}","typeGuard":"fn is_two_listings(v: &Value) -> bool {\n    v.is_array() && v.as_array().unwrap().len() >= 2\n    && v[0].pointer(\"/data/children\").is_some()\n}","tryCatchPattern":"match parse_thread_json(&root) {\n    Ok((post, comments, mores)) => /* ... */,\n    Err(e) if e.to_string().contains(\"resposta inesperada\") => {\n        eprintln!(\"formato de resposta não reconhecido; salve o corpo bruto p/ debug\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Log the raw response body whenever parsing fails so shape changes are visible","Pre-check root.is_array() and length >= 2 before parsing","Pin/refresh fixtures used with thread_from_fixture against the live API","Detect HTML/block-page responses before handing them to the parser"],"tags":["json","parsing","reddit","unexpected-shape"],"backgroundTag":"unexpected-response-shape","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"}