{"record":{"id":"1ef6382e0b79c7ce","repo":"tonhowtf/omniget","slug":"documento-sem-cat-logo","errorCode":null,"errorMessage":"documento sem catálogo: {}","messagePattern":"documento sem catálogo: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/pdf_write.rs","lineNumber":796,"sourceCode":"            .ok_or_else(|| anyhow!(\"página {} não existe\", e.page))?;\n        let parent = if e.level == 0 {\n            None\n        } else {\n            parents.get(e.level as usize - 1).copied()\n        };\n        let bookmark = lopdf::Bookmark::new(e.title.clone(), [0.0, 0.0, 0.0], 0, page_id);\n        let id = doc.add_bookmark(bookmark, parent);\n        parents.truncate(e.level as usize);\n        parents.push(id);\n    }\n    // `build_outline` monta a árvore e devolve o id, mas quem aponta para\n    // ela é o catálogo — sem isto o leitor não mostra sumário nenhum.\n    if let Some(outline_id) = doc.build_outline() {\n        let root = doc\n            .trailer\n            .get(b\"Root\")\n            .and_then(Object::as_reference)\n            .map_err(|e| anyhow!(\"documento sem catálogo: {}\", e))?;\n        if let Ok(catalog) = doc.get_dictionary_mut(root) {\n            catalog.set(\"Outlines\", Object::Reference(outline_id));\n            catalog.set(\"PageMode\", Object::Name(b\"UseOutlines\".to_vec()));\n        }\n    }\n\n    let out = out_path(&opts.input, &opts.output_dir, &opts.suffix, \"-sumario\")?;\n    doc.save(&out).map_err(|e| anyhow!(\"não gravei: {}\", e))?;\n    Ok(WriteItem {\n        input: opts.input.clone(),\n        output: Some(out.to_string_lossy().to_string()),\n        pages: pages.len(),\n        note: format!(\"{} entradas\", entries.len()),\n        ok: true,\n        error: None,\n    })\n}\n","sourceCodeStart":778,"sourceCodeEnd":814,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/pdf_write.rs#L778-L814","documentation":"After building the outline, write_outline reads the trailer's Root (catalog) reference with doc.trailer.get(b\"Root\").and_then(Object::as_reference); if that lookup fails the error is wrapped as \"documento sem catálogo\" (\"document without catalog\"). The catalog is required to attach the Outlines reference so PDF viewers show the bookmark tree.","triggerScenarios":"Calling write_outline on a PDF whose trailer lacks a Root entry or whose Root is not an indirect reference (e.g. heavily stripped or hand-crafted documents).","commonSituations":"Corrupted trailers after an interrupted download; PDFs post-processed by tools that rewrote the trailer; minimal/generated PDFs with a missing or inline Root object.","solutions":["Repair the PDF with qpdf (qpdf broken.pdf fixed.pdf) to rebuild a proper trailer/catalog.","Re-export the PDF from the originating application.","Inspect the wrapped lopdf error in the message for the exact trailer problem.","Use lopdf to delete and re-add a Root catalog object before writing the outline."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"let doc = lopdf::Document::load(&opts.input)?;\nif doc.trailer.get(b\"Root\").is_err() {\n    return Err(anyhow!(\"{}: PDF has no catalog; repair with qpdf\", opts.input));\n}","typeGuard":null,"tryCatchPattern":"match write_outline(&opts) {\n    Err(e) if e.to_string().contains(\"documento sem catálogo\") => {\n        eprintln!(\"repairing input PDF and retrying\");\n        std::process::Command::new(\"qpdf\").args([&opts.input, &repaired]).status()?;\n        // retry with repaired file\n    }\n    other => other?,\n}","preventionTips":["Reject/repair PDFs whose trailer lacks Root before outline operations.","Verify integrity of downloaded PDFs (complete transfer, checksum) before editing.","Keep qpdf available as a repair fallback in batch pipelines."],"tags":["pdf","outline","corrupt-file","trailer"],"backgroundTag":"internal-invariant-violation","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"}