tonhowtf/omniget · error

não achei a assinatura %PDF- — o arquivo não parece um PDF

Error message

não achei a assinatura %PDF- — o arquivo não parece um PDF

What it means

`rebuild_xref` requires the input bytes to contain a `%PDF-` signature, located with `find_first`. If the marker is absent anywhere in the file, it refuses to proceed because it cannot determine where the PDF body starts. The error says the file does not look like a PDF at all.

Solutions

  1. Open the file in a hex/text viewer and confirm it starts with `%PDF-`; if not, the repair path cannot help
  2. Re-download or re-export the file from its original source
  3. Strip email/mime wrappers if the file is an embedded attachment (the PDF may be base64 inside)
  4. Check file size — a 0-byte or few-hundred-byte 'PDF' is almost certainly not one

Example fix

// before
let data = std::fs::read("broken.pdf")?;
let (bytes, objs) = rebuild_xref(&data)?;
// after
let data = std::fs::read("broken.pdf")?;
if !data.windows(5).any(|w| w == b"%PDF-") {
    eprintln!("not a PDF — aborting repair");
    return Ok(());
}
let (bytes, objs) = rebuild_xref(&data)?;
Defensive patterns

Strategy: validation

Validate before calling

fn looks_like_pdf(data: &[u8]) -> bool {
    data.windows(5).any(|w| w == b"%PDF-")
}
// usage: if !looks_like_pdf(&data) { reject the file before calling rebuild_xref }

Type guard

fn is_pdf(data: &[u8]) -> bool {
    data.len() > 100 && data.windows(1024.min(data.len())).any(|w| w.starts_with(b"%PDF-"))
}

Try / catch

match rebuild_xref(&data) {
    Err(e) if e.to_string().contains("%PDF-") => {
        eprintln!("input is not a PDF; re-download or convert the file first");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Passing an empty file, a text/HTML error page saved as .pdf, an encrypted/proprietary container, or a truncated download that lost the header to `rebuild_xref` (or to `run`, which calls it).

Common situations: Downloads that returned an HTML login/error page with a .pdf filename; files uploaded over FTP in ASCII mode corrupting the header; users renaming unrelated files to .pdf; attempting repair on an empty 0-byte file.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/332a13fe5983aba6. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/pdf_repair.rs:346

    for i in 0..n.min(header.len() / 2) {
        let num = header[i * 2] as u32;
        let start = first + header[i * 2 + 1];
        let stop = if i + 1 < n.min(header.len() / 2) {
            first + header[i * 2 + 3]
        } else {
            decoded.len()
        };
        if start <= stop && stop <= decoded.len() {
            out.push((num, decoded[start..stop].to_vec()));
        }
    }
    out
}

/// Reescreve o arquivo com uma xref nova no fim. Devolve `(bytes, objetos)`.
pub fn rebuild_xref(data: &[u8]) -> anyhow::Result<(Vec<u8>, usize)> {
    let head = find_first(data, b"%PDF-")
        .ok_or_else(|| anyhow!("não achei a assinatura %PDF- — o arquivo não parece um PDF"))?;
    // Lixo antes do cabeçalho desloca todos os offsets: corta fora.
    let body = &data[head..];
    let objects = scan_objects(body);
    if objects.is_empty() {
        return Err(anyhow!(
            "nenhum objeto encontrado — arquivo vazio ou cifrado"
        ));
    }

    let mut out = body.to_vec();
    if !out.ends_with(b"\n") {
        out.push(b'\n');
    }
    let mut by_num: std::collections::BTreeMap<u32, (usize, u16)> =
        objects.iter().map(|(n, o, g)| (*n, (*o, *g))).collect();

    // PDF 1.5+ comprime objeto dentro de objeto. Reescreve cada um solto no
    // fim do arquivo — é o que deixa a xref plana voltar a fazer sentido.

View on GitHub (pinned to 8600b91f42)