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
- Verify File.exist? and File.readable? before loading
- Check the first bytes are '%PDF-' magic before calling open_file
- If the path is fine but content is suspect, read the bytes and use Pdfium::Document.open_bytes so you control the input
- 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
- Validate '%PDF-' magic bytes on every upload before any pdfium call
- Rescue PasswordError separately from PdfiumError so encrypted files get a password flow instead of a generic failure
- Never trust client-declared MIME types; check content
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
- Failed to load document from memory, pointer is NULL.
- Failed to load document from IO, pointer is NULL.
- Failed to create new document
- Failed to save document
- Failed to load page #{page_index}, pointer is NULL.
AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21).
Data as JSON: /api/errors/79c395d52a3bf6e4.
Report an issue: GitHub.