{"record":{"id":"d72cc28a9dd4c958","repo":"tonhowtf/omniget","slug":"n-o-gravei-pdf-redact","errorCode":null,"errorMessage":"não gravei {}: {}","messagePattern":"não gravei (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/pdf_redact.rs","lineNumber":893,"sourceCode":"                Some(raw) => redact_page(&mut doc, page_id, raw, rs, opts.bar)?,\n                None => (false, 0, \"página não abriu no PDFium\".to_string()),\n            }\n        };\n        if !surgical {\n            fallback.push(*no);\n        }\n        chars_removed += removed;\n        by_page.push(PageReport {\n            page: *no,\n            areas: rs.len(),\n            chars_removed: removed,\n            mode: if surgical { \"text\" } else { \"raster\" }.into(),\n            note,\n        });\n    }\n\n    doc.save(&output)\n        .map_err(|e| anyhow!(\"não gravei {}: {}\", output.display(), e))?;\n\n    // Conferência: o que ainda aparece dentro da região tem que virar pixel.\n    report(progress, \"progress\", 2, 4, Some(\"conferindo\".into()));\n    let mut leftovers = 0usize;\n    let out_s = output.to_string_lossy().to_string();\n    if let Ok(after) = pdf::read_raw_chars(&out_s, None, \"\") {\n        for page in &after {\n            let Some(rs) = rects.get(&page.number) else {\n                continue;\n            };\n            let n = page\n                .chars\n                .iter()\n                .filter(|c| !c.ch.is_whitespace() && !c.empty_box())\n                .filter(|c| {\n                    let (cx, cy) = c.center();\n                    any_inside(rs, cx, cy)\n                })","sourceCodeStart":875,"sourceCodeEnd":911,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/pdf_redact.rs#L875-L911","documentation":"This error is raised in the redaction tool's `run` when `doc.save(&output)` fails after redaction regions were applied. It wraps the underlying PDF write error with the output path and original error text via `anyhow!`, so the message literally means 'did not write <path>: <cause>'. It indicates the redacted document could not be persisted to disk.","triggerScenarios":"Calling `run` (via `live_redact_deixa_o_check_limpo`) where the output path is unwritable: invalid directory, missing parent folder, permission denied, disk full, path locked by another process, or a failure inside the PDF library while serializing the modified document.","commonSituations":"Output directory was deleted or renamed between selection and save; running the app without write permission to the chosen folder; saving to a file still open in a PDF viewer (Windows file locking); disk quota/full disk; output path containing invalid characters for the filesystem.","solutions":["Check the underlying error text after the colon — it names the real cause (NotFound, PermissionDenied, storage full, etc.)","Verify the output directory exists and is writable before running redaction","Close any program that has the output file open (viewers keep write locks on Windows)","Free disk space or write to a different volume","If the PDF library fails to serialize, try saving to a fresh temp path then rename into place"],"exampleFix":"// before\nlet out = PathBuf::from(\"C:/Program Files/app/output.pdf\");\ndoc.save(&out).map_err(|e| anyhow!(\"não gravei {}: {}\", out.display(), e))?;\n// after\nlet out = dirs::document_dir().unwrap().join(\"redacted.pdf\");\nif let Some(parent) = out.parent() { std::fs::create_dir_all(parent)?; }\ndoc.save(&out).map_err(|e| anyhow!(\"não gravei {}: {}\", out.display(), e))?;","handlingStrategy":"try-catch","validationCode":"// Rust\nfn ensure_writable(path: &std::path::Path) -> anyhow::Result<()> {\n    let dir = path.parent().ok_or_else(|| anyhow!(\"sem diretório\"))?;\n    if !dir.exists() { std::fs::create_dir_all(dir)?; }\n    let probe = dir.join(\".write_probe\");\n    std::fs::write(&probe, b\"\")?;\n    std::fs::remove_file(&probe)?;\n    if path.exists() && std::fs::metadata(path)?.permissions().readonly() {\n        anyhow::bail!(\"arquivo de saída é read-only\");\n    }\n    Ok(())\n}","typeGuard":"fn is_writable_output(path: &std::path::Path) -> bool {\n    path.parent().map(|d| d.is_dir()).unwrap_or(false)\n        && std::fs::OpenOptions::new().append(true).create(true)\n            .open(path).is_ok()\n}","tryCatchPattern":"match run(/* ... */) {\n    Err(e) if e.to_string().starts_with(\"não gravei\") => {\n        eprintln!(\"falha ao gravar o PDF: {}. Verifique permissões e espaço em disco.\", e);\n    }\n    Err(e) => return Err(e),\n    Ok(report) => { /* success */ }\n}","preventionTips":["Always create the output parent directory with create_dir_all before saving","Save to a temp file in the same directory and rename on success (atomic write)","Pre-check disk free space for raster-mode output, which can be much larger","Prompt the user to close PDF viewers before writing to an existing file"],"tags":["pdf","file-write","io","rust"],"backgroundTag":"file-write-failed","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"}