docusealco/docuseal · error · Pdfium::PdfiumError

Page index #{page_index} out of range (0..#{page_count - 1})

Error message

Page index #{page_index} out of range (0..#{page_count - 1})

What it means

Validation guard in Document#get_page: the index must be an Integer, greater than or equal to 0, and strictly less than page_count. It fires for negative indexes, indexes at or above page_count, and non-Integer inputs such as nil, strings, or floats. The message includes the valid range (0..page_count-1), which makes off-by-one mistakes (1-based user input vs 0-based API) easy to spot.

Source

Thrown at lib/pdfium.rb:700

        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)

        acc << [bookmark_title(bookmark), *destination(Pdfium.FPDFBookmark_GetDest(@document_ptr, bookmark))]
        acc.concat(bookmarks(bookmark, seen))

        bookmark = Pdfium.FPDFBookmark_GetNextSibling(@document_ptr, bookmark)
      end

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Convert and normalize input: idx = Integer(params[:page]) rescue 0, then subtract 1 if the input is 1-based
  2. Always go through doc.get_page(idx), which validates, instead of constructing Pdfium::Page directly
  3. Re-read doc.page_count after document mutations (import_pages resets the memoized count) before indexing

Example fix

# before
page = doc.get_page(params[:page]) # String '2' or 1-based input raises

# after
idx = Integer(params[:page], 10) rescue 0
idx -= 1 if params[:one_based]
idx = idx.clamp(0, doc.page_count - 1)
page = doc.get_page(idx)
Defensive patterns

Strategy: validation

Validate before calling

def valid_page_index?(doc, idx)
  idx.is_a?(Integer) && idx >= 0 && idx < doc.page_count
end

raise ArgumentError, 'page out of range' unless valid_page_index?(doc, idx)

Type guard

def integer_page_index?(value)
  value.is_a?(Integer) && value >= 0
end

Try / catch

begin
  page = doc.get_page(idx)
rescue Pdfium::PdfiumError => e
  raise unless e.message.start_with?('Page index ')
  idx = idx.clamp(0, doc.page_count - 1)
  retry
end

Prevention

When it happens

Trigger: get_page(page_count) when targeting the last page (1-based input not converted); get_page(-1); get_page(params[:page]) where the param is the String '2' or nil; a stale page_count assumption after import_pages changed the document.

Common situations: User-facing page numbers are 1-based while this API is 0-based; JSON request params arriving as strings; iterating 1..page_count instead of 0...page_count.

Related errors


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