tonhowtf/omniget · error

ghostscript não gerou nada

Error message

ghostscript não gerou nada: {}

What it means

Thrown when the Ghostscript process ran to completion but the expected output PDF is missing or has zero bytes; the message embeds Ghostscript's stderr for diagnosis. It is a post-execution sanity check in run_ghostscript ensuring `-sOutputFile` actually produced a usable file.

Solutions

  1. Read the stderr embedded in the error message — it contains Ghostscript's own diagnostic (e.g. 'Unrecoverable error', permission denied)
  2. Try the "rebuild" repair mode, which reconstructs the PDF in pure Rust without Ghostscript
  3. Check the input PDF opens elsewhere (e.g. `gs -dNOPAUSE -dBATCH -sDEVICE=nullpage input.pdf`) to confirm gs can parse it at all
  4. Verify the output directory is writable and has free disk space; ensure no concurrent run targets the same output path
  5. If the PDF is password-protected, unlock it before repair

Example fix

// before
pdf_repair::run(RepairOptions { mode: "gs".into(), inputs, ..Default::default() }, progress).await?;
// after
match pdf_repair::run(RepairOptions { mode: "gs".into(), inputs, ..Default::default() }, progress).await {
    Ok(res) => res,
    Err(e) if e.to_string().contains("não gerou nada") =>
        pdf_repair::run(RepairOptions { mode: "rebuild".into(), inputs, ..Default::default() }, progress).await?,
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: can Ghostscript even read the input?
let probe = tokio::process::Command::new(&gs)
    .args(["-dNOPAUSE","-dBATCH","-sDEVICE=nullpage"])
    .arg(&input)
    .output().await?;
if !probe.status.success() { anyhow::bail!("gs não consegue ler a entrada: {}", String::from_utf8_lossy(&probe.stderr)); }
// Also ensure output dir is writable and has space
let dir = output.parent().unwrap_or(Path::new("."));
let dir = dir.to_path_buf();
tokio::fs::create_dir_all(&dir).await?;

Type guard

fn output_dir_writable(dir: &std::path::Path) -> bool {
    let probe = dir.join(".wtest");
    std::fs::write(&probe, b"x").is_ok() && std::fs::remove_file(&probe).is_ok()
}

Try / catch

match run_ghostscript(&gs, &input, &output).await {
    Ok(()) => {},
    Err(e) if e.to_string().contains("não gerou nada") => {
        log::warn!("gs falhou: {e}; tentando modo rebuild");
        rebuild_pdf(&input, &output).await?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: gs exits after writing nothing: input PDF is so corrupt pdfwrite fails; output directory/path not writable; output path overwritten by another concurrent run; gs erroring on an unsupported or encrypted input; disk full.

Common situations: Repairing a badly truncated PDF where pdfwrite bails out; running two repairs of the same input concurrently racing on the same `-reparado.pdf` output; read-only output directory; encrypted/password-protected PDF passed without handling; out-of-disk space.

Related errors


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

Appendix: source

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

async fn open_pages(path: &str) -> Option<usize> {
    let p = path.to_string();
    tokio::task::spawn_blocking(move || super::pdf::info(&p, None).ok().map(|i| i.pages))
        .await
        .ok()
        .flatten()
}

async fn run_ghostscript(gs: &Path, input: &Path, output: &Path) -> anyhow::Result<()> {
    let out = crate::core::process::command(gs)
        .args(["-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pdfwrite"])
        .arg(format!("-sOutputFile={}", output.display()))
        .arg(input)
        .output()
        .await
        .map_err(|e| anyhow!("ghostscript nao iniciou: {}", e))?;
    if !output.exists() || std::fs::metadata(output).map(|m| m.len()).unwrap_or(0) == 0 {
        return Err(anyhow!(
            "ghostscript não gerou nada: {}",
            String::from_utf8_lossy(&out.stderr).trim()
        ));
    }
    Ok(())
}

fn output_path(opts: &RepairOptions, inp: &Path) -> anyhow::Result<PathBuf> {
    let dir = if opts.output_dir.trim().is_empty() {
        inp.parent().map(|p| p.to_path_buf()).unwrap_or_default()
    } else {
        PathBuf::from(opts.output_dir.trim())
    };
    std::fs::create_dir_all(&dir)?;
    let stem = inp
        .file_stem()
        .map(|s| s.to_string_lossy().to_string())
        .unwrap_or_else(|| "documento".into());

View on GitHub (pinned to 8600b91f42)