docusealco/docuseal · error · Pdfium::PdfiumError

Document is closed.

Error message

Document is closed.

What it means

Guard raised by Document#ensure_not_closed! when any operation is attempted on a document after close. close nulls the document handle, closes every cached page, exits the form-fill environment and frees buffers, so later use would be a use-after-free at the FFI boundary; this guard converts that into a Ruby exception. The block forms of Document.create/open_file/open_bytes/open_io close the document in an ensure clause, so using the doc outside the block is the most common trigger.

Source

Thrown at lib/pdfium.rb:693

      end

      doc = new(doc_ptr, [file_access, get_block, io])

      return doc unless block_given?

      begin
        yield doc
      ensure
        doc.close
      end
    end

    def closed?
      @closed
    end

    def ensure_not_closed!
      raise PdfiumError, 'Document is closed.' if closed?
    end

    def get_page(page_index)
      ensure_not_closed!

      unless page_index.is_a?(Integer) && page_index >= 0 && page_index < page_count
        raise PdfiumError, "Page index #{page_index} out of range (0..#{page_count - 1})"
      end

      @pages[page_index] ||= Page.new(self, page_index)
    end

    def bookmarks(parent = nil, seen = Set.new)
      acc = []
      bookmark = Pdfium.FPDFBookmark_GetFirstChild(@document_ptr, parent)

      until bookmark.null?
        break unless seen.add?(bookmark.address)

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Perform all work inside the open block, or use the non-block form and call doc.close yourself in an ensure
  2. Check doc.closed? before reuse and re-open the document when true
  3. Return extracted data (strings, arrays, rendered bytes) rather than Document/Page objects from the scope that owns their lifecycle

Example fix

# before
doc = nil
Pdfium::Document.open_file(path) { |d| doc = d }
doc.page_count # raises Document is closed.

# after
Pdfium::Document.open_file(path) do |doc|
  @count = doc.page_count
end
Defensive patterns

Strategy: validation

Validate before calling

if doc.closed?
  doc = Pdfium::Document.open_file(path) # or raise/re-open from source bytes
end

Try / catch

begin
  doc.get_page(0)
rescue Pdfium::PdfiumError => e
  raise unless e.message == 'Document is closed.'
  reopen_and_retry
end

Prevention

When it happens

Trigger: Capturing the yielded doc from Pdfium::Document.open_file(path) { |d| } and calling methods on it after the block; saving a document after its open block returned; storing the doc in an instance variable and touching it in a later request or job.

Common situations: Rails controllers that open with the block form but stash the doc for the view; background jobs returning Document objects instead of extracted data; retry code that reuses a doc already closed by ensure.

Related errors


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