docusealco/docuseal · error · Pdfium::PdfiumError

Failed to load redacted image

Error message

Failed to load redacted image

What it means

Raised by Pdfium::Page#load_image_jpeg (lib/pdfium.rb:1519) after FPDFImageObj_LoadJpegFileInline returns 0, meaning PDFium refused to embed the supplied JPEG bytes into the existing image object. It occurs during image redaction: redact_image_objects extracts the original bitmap, the caller's block paints blackout pixel rects and re-encodes to JPEG, and load_image_jpeg pushes that JPEG back into the page object. The raise fires when the re-encoded bytes are not a JPEG PDFium can decode inline, or the target object/page handle is no longer valid.

Source

Thrown at lib/pdfium.rb:1519

    def load_image_jpeg(object_ptr, jpeg)
      get_block = FFI::Function.new(:int, %i[pointer ulong pointer ulong]) do |_param, position, out, size|
        out.put_bytes(0, jpeg.byteslice(position, size) || ''.b)

        1
      end

      file_access = Pdfium::FPDF_FILEACCESS.new
      file_access[:m_FileLen] = jpeg.bytesize
      file_access[:m_GetBlock] = get_block
      file_access[:m_Param] = FFI::Pointer::NULL

      pages_ptr = FFI::MemoryPointer.new(:pointer, 1)
      pages_ptr.write_pointer(@page_ptr)

      result = Pdfium.FPDFImageObj_LoadJpegFileInline(pages_ptr, 1, object_ptr, file_access)

      raise PdfiumError, 'Failed to load redacted image' if result.zero?
    end

    def text_objects
      return @text_objects if @text_objects

      ensure_not_closed!

      @text_objects = []

      object_count = Pdfium.FPDFPage_CountObjects(page_ptr)

      return @text_objects if object_count.zero?

      text_page = Pdfium.FPDFText_LoadPage(page_ptr)

      if text_page.null?
        Pdfium.check_last_error("Failed to load text page #{page_index}")

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Verify the value returned by the redaction block is non-empty and starts with JPEG magic bytes (\xFF\xD8) before returning it, so load_image_jpeg is skipped (jpeg falsy) for bad encodes.
  2. Re-encode the redacted bitmap as a baseline (non-progressive) RGB JPEG in the block passed to redact_image_objects.
  3. Wrap the redaction call per page in begin/rescue Pdfium::PdfiumError and fall back to drawing opaque rects only (draw_redaction_rects) when inline reload fails.
  4. Make sure the page handle is not closed or reloaded while the redaction block iterates objects; perform redaction before any flatten/rotate/reload on that page object.

Example fix

# before (block may return garbage/empty encode)
page.redact_image_objects(rects) do |bitmap, pixel_rects|
  RedactEncoder.to_jpeg(bitmap, pixel_rects)
end

# after (skip reload for undecodable encodes)
page.redact_image_objects(rects) do |bitmap, pixel_rects|
  jpeg = RedactEncoder.to_jpeg(bitmap, pixel_rects)
  jpeg if jpeg.is_a?(String) && jpeg.bytesize > 4 && jpeg.getbyte(0) == 0xFF && jpeg.getbyte(1) == 0xD8
end
Defensive patterns

Strategy: try-catch

Validate before calling

# Validate the JPEG your redaction block produces before returning it
def redactable_jpeg?(jpeg)
  jpeg.is_a?(String) &&
    jpeg.bytesize > 4 &&
    jpeg.getbyte(0) == 0xFF &&
    jpeg.getbyte(1) == 0xD8 &&
    jpeg.getbyte(-2) == 0xFF && # rough SOI/EOI sanity
    jpeg.getbyte(-1) == 0xD9
end

Try / catch

begin
  page.redact_image_objects(rects) { |bitmap, pixel_rects| encoder.call(bitmap, pixel_rects) }
rescue Pdfium::PdfiumError => e
  Rails.logger.warn("redaction skipped page #{page.page_index}: #{e.message}")
  page.draw_redaction_rects(rects) # opaque-rect fallback, content still covered
end

Prevention

When it happens

Trigger: Calling redact_image_objects with a block whose return value is nil-check-passing but undecodable: an empty string, PNG or raw bytes mislabeled as JPEG, CMYK/YCCK or progressive JPEGs that the inline loader rejects, or a truncated encode from a crashed encoder. Also triggered when object_ptr is not a valid FPDF_PAGEOBJ_IMAGE anymore, or when the page was closed/reloaded (via close, flatten, rotate) between extract_image_bitmap and the reload call.

Common situations: Redacting scanned/faxed PDFs whose source images use CMYK JPEG colorspaces; a redaction encoder that silently rescues exceptions and returns '' ; running redaction concurrently with another thread calling reload or close on the same page; libpdfium version changes tightening which JPEGs the inline loader accepts.

Related errors


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