tonhowtf/omniget · error
documento sem catálogo
Error message
documento sem catálogo: {} What it means
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.
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.
Defensive patterns
Strategy: try-catch
Validate before calling
let doc = lopdf::Document::load(&opts.input)?;
if doc.trailer.get(b"Root").is_err() {
return Err(anyhow!("{}: PDF has no catalog; repair with qpdf", opts.input));
} Try / catch
match write_outline(&opts) {
Err(e) if e.to_string().contains("documento sem catálogo") => {
eprintln!("repairing input PDF and retrying");
std::process::Command::new("qpdf").args([&opts.input, &repaired]).status()?;
// retry with repaired file
}
other => other?,
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- não limpei o sumário antigo
- nenhum objeto encontrado — arquivo vazio ou cifrado
- não achei o catálogo (/Root) do documento
- página não existe
- Failed to read zip entry
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/1ef6382e0b79c7ce.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/pdf_write.rs:796
.ok_or_else(|| anyhow!("página {} não existe", e.page))?;
let parent = if e.level == 0 {
None
} else {
parents.get(e.level as usize - 1).copied()
};
let bookmark = lopdf::Bookmark::new(e.title.clone(), [0.0, 0.0, 0.0], 0, page_id);
let id = doc.add_bookmark(bookmark, parent);
parents.truncate(e.level as usize);
parents.push(id);
}
// `build_outline` monta a árvore e devolve o id, mas quem aponta para
// ela é o catálogo — sem isto o leitor não mostra sumário nenhum.
if let Some(outline_id) = doc.build_outline() {
let root = doc
.trailer
.get(b"Root")
.and_then(Object::as_reference)
.map_err(|e| anyhow!("documento sem catálogo: {}", e))?;
if let Ok(catalog) = doc.get_dictionary_mut(root) {
catalog.set("Outlines", Object::Reference(outline_id));
catalog.set("PageMode", Object::Name(b"UseOutlines".to_vec()));
}
}
let out = out_path(&opts.input, &opts.output_dir, &opts.suffix, "-sumario")?;
doc.save(&out).map_err(|e| anyhow!("não gravei: {}", e))?;
Ok(WriteItem {
input: opts.input.clone(),
output: Some(out.to_string_lossy().to_string()),
pages: pages.len(),
note: format!("{} entradas", entries.len()),
ok: true,
error: None,
})
}
View on GitHub (pinned to 8600b91f42)