docusealco/docuseal · error · Pdfium::PdfiumError
Failed to save document
Error message
Failed to save document
What it means
Raised by Document#save when FPDF_SaveAsCopy returns 0. save first runs presave hooks (such as the cleanup hook Page#redact installs) and then check_last_error, which raises the richer message with the PDFium error code when one is set; this plain variant means a zero return with no recorded code. That usually indicates an internally inconsistent document after failed edits or an unsupportable flag combination. Note the write callback streams into the target io as it goes, so the io can hold partial output when this raises.
Source
Thrown at lib/pdfium.rb:800
run_presave_hooks
file_write_mem = FFI::MemoryPointer.new(FPDF_FILEWRITE.size)
file_write_struct = FPDF_FILEWRITE.new(file_write_mem)
file_write_struct[:version] = 1
file_write_struct[:WriteBlock] = FFI::Function.new(:int, %i[pointer pointer ulong]) do |_, data, size|
io.write(data.read_bytes(size))
1
end
result = Pdfium.FPDF_SaveAsCopy(@document_ptr, file_write_mem, flags)
if result.zero?
Pdfium.check_last_error('Failed to save document')
raise PdfiumError, 'Failed to save document'
end
io
end
def cleanup
ensure_not_closed!
Pdfium.FPDF_RemoveOrphanObjects(@document_ptr)
end
def standard_font
@standard_font ||= Pdfium.FPDFText_LoadStandardFont(@document_ptr, 'Helvetica')
end
def add_presave_hook(key, &block)
@presave_hooks[key] ||= block
endView on GitHub (pinned to 004a22c1c8)
Solutions
- Retry with default flags (Pdfium::FPDF_NO_INCREMENTAL) - incremental saves fail on memory-loaded documents
- Save to a fresh StringIO or tempfile to rule out a bad io target
- Call doc.cleanup before save to drop orphaned objects
- If it persists, re-open the original and apply fewer edits per save; update libpdfium since SaveAsCopy fixes land regularly
Example fix
# before
File.open(out, 'wb') { |f| doc.save(f, flags: Pdfium::FPDF_ANNOT) }
# after
File.open(out, 'wb') { |f| doc.save(f, flags: Pdfium::FPDF_NO_INCREMENTAL) } Defensive patterns
Strategy: fallback
Try / catch
begin
File.open(out, 'wb') { |f| doc.save(f) }
rescue Pdfium::PdfiumError => e
raise unless e.message == 'Failed to save document'
buffer = StringIO.new
doc.save(buffer, flags: Pdfium::FPDF_NO_INCREMENTAL) # retry, non-incremental
File.binwrite(out, buffer.string)
end Prevention
- Default to FPDF_NO_INCREMENTAL; incremental save only works for file-backed loads
- Treat the target io as dirty after a failed save - the callback may have written partial bytes
- Run doc.cleanup before saving edited documents
When it happens
Trigger: Saving after page edits (redact, object removal) that left the page tree inconsistent; using incremental-save flags on a document loaded from memory; a presave hook mutating the document into a bad state; saving an already damaged PDF that pdfium repaired at load time.
Common situations: Redaction pipelines over malformed PDFs; documents processed by mixed toolchains; docs loaded from bytes then saved with non-default flags.
Related errors
- Failed to create new document
- Failed to load document from file '#{file_path}', pointer is
- Failed to load document from memory, pointer is NULL.
- Failed to load document from IO, pointer is NULL.
- Failed to load page #{page_index}, pointer is NULL.
AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21).
Data as JSON: /api/errors/9f05a648787d633c.
Report an issue: GitHub.