docusealco/docuseal · error · Pdfium::PdfiumError

Failed to create bitmap (FPDFBitmap_Create returned NULL)

Error message

Failed to create bitmap (FPDFBitmap_Create returned NULL)

What it means

Raised by Page#render_to_bitmap when FPDFBitmap_Create returns NULL for the computed render dimensions. This is a native allocation failure: the bitmap consumes roughly width*height*4 bytes, so oversized dimensions (large scale values, explicit width/height, or poster-sized pages) exhaust the memory budget. check_last_error runs first with the 'potential pre-existing error' context, but PDFium records no error code for bitmap allocation, so this plain raise is what you see.

Source

Thrown at lib/pdfium.rb:1032

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

      @document.ensure_not_closed!
    end

    def render_to_bitmap(width: nil, height: nil, scale: nil, background_color: 0xFFFFFFFF,
                         flags: FPDF_ANNOT | FPDF_LCD_TEXT | FPDF_NO_NATIVETEXT | FPDF_REVERSE_BYTE_ORDER)
      ensure_not_closed!

      render_width, render_height = calculate_render_dimensions(width, height, scale)

      bitmap_ptr = Pdfium.FPDFBitmap_Create(render_width, render_height, 1)

      if bitmap_ptr.null?
        Pdfium.check_last_error('Failed to create bitmap (potential pre-existing error)')

        raise PdfiumError, 'Failed to create bitmap (FPDFBitmap_Create returned NULL)'
      end

      Pdfium.FPDFBitmap_FillRect(bitmap_ptr, 0, 0, render_width, render_height, background_color)

      Pdfium.FPDF_RenderPageBitmap(bitmap_ptr, page_ptr, 0, 0, render_width, render_height, 0, flags)

      unless form_handle.null?
        Pdfium.FPDF_FFLDraw(form_handle, bitmap_ptr, page_ptr, 0, 0, render_width, render_height, 0, flags)
      end

      buffer_ptr = Pdfium.FPDFBitmap_GetBuffer(bitmap_ptr)
      stride = Pdfium.FPDFBitmap_GetStride(bitmap_ptr)

      bitmap_data = buffer_ptr.read_bytes(stride * render_height)

      [bitmap_data, render_width, render_height]
    ensure
      Pdfium.FPDFBitmap_Destroy(bitmap_ptr) if bitmap_ptr && !bitmap_ptr.null?

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Cap render dimensions: pass explicit width/height clamped to roughly 3000-5000px instead of an unbounded scale
  2. Compute the target pixel count from page.width/height first and skip or downscale when it exceeds a budget
  3. Free other documents and bitmaps before large renders; raise the container memory limit
  4. Add Pdfium::FPDF_RENDER_LIMITEDIMAGECACHE to the flags to bound pdfium's image cache

Example fix

# before
bitmap = page.render_to_bitmap(scale: 8)

# after
MAX = 3000
scale = [8, (MAX / page.width).to_f, (MAX / page.height).to_f].min
bitmap = page.render_to_bitmap(scale: scale)
Defensive patterns

Strategy: validation

Validate before calling

MAX_SIDE = 3000
MAX_PIXELS = 8_000_000

def clamped_scale(page, desired)
  s = [(desired || 1).to_f, 0.1].max
  s = [s, MAX_SIDE / page.width, MAX_SIDE / page.height].min
  s = [s, Math.sqrt(MAX_PIXELS / (page.width * page.height))].min
  [s, 0.1].max
end

Try / catch

begin
  page.render_to_bitmap(scale: scale)
rescue Pdfium::PdfiumError => e
  raise unless e.message.include?('Failed to create bitmap')
  page.render_to_bitmap(width: 1500, height: nil) # degrade gracefully
end

Prevention

When it happens

Trigger: render_to_bitmap(scale: 8) on a large page; passing width: 20000 explicitly; rendering A0/architecture drawings at default scale; rendering while the process is already near its memory cap.

Common situations: High-DPI thumbnail generation; zoomed-view rendering features; unvalidated user-supplied render dimensions (a denial-of-service vector); low container memory limits.

Related errors


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