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
- Read the stderr embedded in the error message — it contains Ghostscript's own diagnostic (e.g. 'Unrecoverable error', permission denied)
- Try the "rebuild" repair mode, which reconstructs the PDF in pure Rust without Ghostscript
- Check the input PDF opens elsewhere (e.g. `gs -dNOPAUSE -dBATCH -sDEVICE=nullpage input.pdf`) to confirm gs can parse it at all
- Verify the output directory is writable and has free disk space; ensure no concurrent run targets the same output path
- 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
- Log the embedded Ghostscript stderr — it names the real cause (unreadable input, encryption, disk)
- Never run concurrent repairs that write the same output path; include the input stem/pid in output names
- Unlock encrypted PDFs before gs repair
- Check free disk space before large batch repairs
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)