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
- Perform all work inside the open block, or use the non-block form and call doc.close yourself in an ensure
- Check doc.closed? before reuse and re-open the document when true
- 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
- Prefer the block forms (open_file/open_bytes/open_io with a block); they close in ensure and make this class of bug impossible
- Never leak Document objects across request/job boundaries; pass extracted data instead
- Assert !doc.closed? in test helpers that share documents across examples
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
- Page is closed.
- Failed to create new document
- Failed to load document from file '#{file_path}', pointer is
- Failed to load document from memory, pointer is NULL.
- Failed to load document from IO, pointer is NULL.
AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21).
Data as JSON: /api/errors/d0590c76eb9ad323.
Report an issue: GitHub.