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
    end

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Retry with default flags (Pdfium::FPDF_NO_INCREMENTAL) - incremental saves fail on memory-loaded documents
  2. Save to a fresh StringIO or tempfile to rule out a bad io target
  3. Call doc.cleanup before save to drop orphaned objects
  4. 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

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


AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21). Data as JSON: /api/errors/9f05a648787d633c. Report an issue: GitHub.