docusealco/docuseal · error · Pdfium::PdfiumError

Failed to import pages

Error message

Failed to import pages

What it means

Pdfium::Document#import_pages wraps FPDF_ImportPages from the PDFium C API and raises PdfiumError 'Failed to import pages' when the native call returns 0. Failure means the requested pages could not be inserted into the destination document: an invalid page specification string, an out-of-range page number, a source document that is closed or cannot yield pages (corrupt or extraction-restricted), or FFI marshalling problems after a pdfium upgrade. The subsequent FPDF_ImportAcroForm call only runs on success.

Source

Thrown at lib/pdfium.rb:571

    def page_count
      @page_count ||= Pdfium.FPDF_GetPageCount(@document_ptr)
    end

    def encrypted?
      Pdfium.FPDF_GetSecurityHandlerRevision(@document_ptr) >= 0
    end

    def form?
      Pdfium.FPDF_GetFormType(@document_ptr) != Pdfium::FORMTYPE_NONE
    end

    def import_pages(src_doc, pages: nil, index: nil)
      ensure_not_closed!

      result = Pdfium.FPDF_ImportPages(@document_ptr, src_doc.document_ptr, pages, index || page_count)

      raise PdfiumError, 'Failed to import pages' if result.zero?

      Pdfium.FPDF_ImportAcroForm(@document_ptr, src_doc.document_ptr)

      @page_count = nil

      result
    end

    def self.create
      doc_ptr = Pdfium.FPDF_CreateNewDocument()

      if doc_ptr.null?
        Pdfium.check_last_error('Failed to create new document')

        raise PdfiumError, 'Failed to create new document'
      end

      doc = new(doc_ptr)

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Log the pages argument, both documents' page_count, and encryption status right before the call, and validate the 1-based range.
  2. Ensure both documents are open and readable - import from a freshly opened source when in doubt.
  3. Reproduce outside the app with qpdf or pdfium tooling on the same file pair to confirm the documents themselves merge.
  4. Repair/normalize inputs first (e.g. qpdf --decrypt or a re-save) and retry.
  5. After pdfium upgrades, verify the FPDF_ImportPages signature and string marshalling in the FFI layer.

Example fix

# before
result = doc.import_pages(src_doc, pages: params[:pages])

# after
pages = params[:pages].to_s
if pages.present?
  nums = pages.scan(/\d+/).map(&:to_i)
  raise ArgumentError, 'page out of range' if nums.any? { |n| n < 1 || n > src_doc.page_count }
end
result = doc.import_pages(src_doc, pages: pages.presence)
Defensive patterns

Strategy: validation

Validate before calling

pages = params[:pages].to_s
if pages.present?
  nums = pages.scan(/\d+/).map(&:to_i)
  raise ArgumentError, 'page out of range' if nums.any? { |n| n < 1 || n > src_doc.page_count }
end
doc.import_pages(src_doc, pages: pages.presence)

Try / catch

begin
  doc.import_pages(src_doc, pages: pages)
rescue Pdfium::PdfiumError => e
  mark_merge_failed(document_id)
  Rails.logger.error("import_pages failed: #{e.message} pages=#{pages}")
end

Prevention

When it happens

Trigger: Passing a pages string like '0', or '5' for a 3-page source, or a malformed range; src_doc already closed (only the destination's ensure_not_closed! is checked here); merging secured or encrypted PDFs that forbid extraction; pdfium library version drift changing argument expectations.

Common situations: Template merge features with user-supplied page ranges; password-protected or permissions-locked PDF uploads; upgrading the pdfium binary without re-checking bindings; corrupted uploads that open but fail deep operations.

Related errors


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