{"record":{"id":"b9f46871b5e5a0a9","repo":"docusealco/docuseal","slug":"failed-to-load-document-from-io-pointer-is-null","errorCode":null,"errorMessage":"Failed to load document from IO, pointer is NULL.","messagePattern":"Failed to load document from IO, pointer is NULL\\.","errorType":"exception","errorClass":"Pdfium::PdfiumError","httpStatus":null,"severity":"error","filePath":"lib/pdfium.rb","lineNumber":674,"sourceCode":"\n        bytes = io.read(size).to_s\n\n        out.put_bytes(0, bytes)\n\n        bytes.bytesize == size ? 1 : 0\n      end\n\n      file_access = Pdfium::FPDF_FILEACCESS.new\n      file_access[:m_FileLen] = io.size\n      file_access[:m_GetBlock] = get_block\n      file_access[:m_Param] = FFI::Pointer::NULL\n\n      doc_ptr = Pdfium.FPDF_LoadCustomDocument(file_access, password)\n\n      if doc_ptr.null?\n        Pdfium.check_last_error('Failed to load document from IO')\n\n        raise PdfiumError, 'Failed to load document from IO, pointer is NULL.'\n      end\n\n      doc = new(doc_ptr, [file_access, get_block, io])\n\n      return doc unless block_given?\n\n      begin\n        yield doc\n      ensure\n        doc.close\n      end\n    end\n\n    def closed?\n      @closed\n    end\n\n    def ensure_not_closed!","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/pdfium.rb#L656-L692","documentation":"Raised by Pdfium::Document.open_io when FPDF_LoadCustomDocument returns NULL. open_io first delegates to open_file when the IO responds to path (after flush); otherwise it installs an FPDF_FILEACCESS read callback backed by io.seek/io.read and declares io.size as m_FileLen. This failure means the callback-based reads came up short (the callback returns 0 on short reads), the declared length was wrong, or the stream is corrupt or encrypted. check_last_error runs first and raises the error-code variant (PasswordError for FPDF_ERR_PASSWORD) when a code was recorded.","triggerScenarios":"An IO whose read(size) returns fewer bytes than requested (socket closed mid-read, wrapper stream exhausted); io.size not matching the true byte length; a non-seekable pipe; a stream another layer already consumed; an encrypted stream without a password.","commonSituations":"Streaming HTTP downloads straight into PDFium; reading from decoding wrapper IOs; StringIO fixtures with wrong size; reusing an IO after an earlier parse consumed it.","solutions":["Call io.rewind and io.binmode, and make sure the IO has not been consumed, before loading","If the stream is not reliably seekable, read it fully (io.read) and use open_bytes instead","Confirm io.size matches the actual content length (callback short-reads fail the whole load)","Rescue Pdfium::PasswordError and retry with the password for encrypted streams"],"exampleFix":"# before\ndoc = Pdfium::Document.open_io(socket_io)\n\n# after - buffer unreliable streams first\ndata = io.read\ndoc = Pdfium::Document.open_bytes(data)","handlingStrategy":"validation","validationCode":"io.binmode\nio.rewind if io.respond_to?(:rewind)\nraise ArgumentError, 'IO must expose #size' unless io.respond_to?(:size) && io.size.positive?\n# if the stream may be short/non-seekable, buffer it instead:\n# Pdfium::Document.open_bytes(io.read)","typeGuard":null,"tryCatchPattern":"begin\n  Pdfium::Document.open_io(io, password)\nrescue Pdfium::PasswordError\n  retry_with_password\nrescue Pdfium::PdfiumError => e\n  data = io.rewind && io.read # salvage: retry once from buffered bytes\n  data ? Pdfium::Document.open_bytes(data, password) : raise\nend","preventionTips":["Remember open_io silently delegates to open_file when the IO responds to path; flush before calling","Use open_io only for genuinely seekable, binary IOs; buffer network streams first","Do not reuse an IO that a previous parse consumed"],"tags":["pdfium","io-streaming","invalid-pdf","ffi","ruby"],"backgroundTag":"stream-read-failed","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}