docusealco/docuseal · error · Pdfium::PdfiumError

Failed to load document from file '#{file_path}', pointer is

Error message

Failed to load document from file '#{file_path}', pointer is NULL.

What it means

Raised by Pdfium::Document.open_file when FPDF_LoadDocument returns a NULL document handle. Pdfium.check_last_error runs first and raises PdfiumError or PasswordError with the PDFium error code (FPDF_ERR_PASSWORD, FPDF_ERR_FORMAT, FPDF_ERR_FILE) when one is set, so this exact plain message means the load returned NULL with no recorded code. That is the classic signature of a missing/unreadable path or bytes that are not a PDF at all.

Source

Thrown at lib/pdfium.rb:606

      doc = new(doc_ptr)

      return doc unless block_given?

      begin
        yield doc
      ensure
        doc.close
      end
    end

    def self.open_file(file_path, password = nil)
      doc_ptr = Pdfium.FPDF_LoadDocument(file_path, password)

      if doc_ptr.null?
        Pdfium.check_last_error("Failed to load document from file '#{file_path}'")

        raise PdfiumError, "Failed to load document from file '#{file_path}', pointer is NULL."
      end

      doc = new(doc_ptr)

      return doc unless block_given?

      begin
        yield doc
      ensure
        doc.close
      end
    end

    def self.open_bytes(bytes, password = nil)
      buffer = FFI::MemoryPointer.new(:char, bytes.bytesize)
      buffer.put_bytes(0, bytes)

      doc_ptr = Pdfium.FPDF_LoadMemDocument(buffer, bytes.bytesize, password)

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Verify File.exist? and File.readable? before loading
  2. Check the first bytes are '%PDF-' magic before calling open_file
  3. If the path is fine but content is suspect, read the bytes and use Pdfium::Document.open_bytes so you control the input
  4. Rescue Pdfium::PasswordError and retry with the password for encrypted files

Example fix

# before
doc = Pdfium::Document.open_file(upload_path)

# after
raise ArgumentError, 'not a PDF' unless File.file?(upload_path) && File.open(upload_path, 'rb') { |f| f.read(5) } == '%PDF-'

doc = Pdfium::Document.open_file(upload_path)
Defensive patterns

Strategy: validation

Validate before calling

def loadable_pdf_file?(path)
  File.file?(path) && File.readable?(path) && File.size(path).positive? &&
    File.open(path, 'rb') { |f| f.read(5) == '%PDF-' }
end

raise ArgumentError, 'not a PDF' unless loadable_pdf_file?(path)

Try / catch

begin
  Pdfium::Document.open_file(path, password)
rescue Pdfium::PasswordError
  prompt_for_password_and_retry
rescue Pdfium::PdfiumError => e
  mark_upload_invalid(path, e.message)
end

Prevention

When it happens

Trigger: open_file('/tmp/gone.pdf') after the tempfile was deleted; a path that points to a directory; a .docx or image renamed to .pdf; a zero-byte file. An encrypted PDF without a password raises the PasswordError variant from check_last_error instead of this message.

Common situations: Processing user uploads without validating content; stale paths from cleaned tmp directories; files still being written when load is attempted; double extensions or client-side MIME spoofing.

Related errors


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