{"record":{"id":"f69213aefc628596","repo":"docusealco/docuseal","slug":"failed-to-load-redacted-image","errorCode":null,"errorMessage":"Failed to load redacted image","messagePattern":"Failed to load redacted image","errorType":"exception","errorClass":"Pdfium::PdfiumError","httpStatus":null,"severity":"error","filePath":"lib/pdfium.rb","lineNumber":1519,"sourceCode":"\n    def load_image_jpeg(object_ptr, jpeg)\n      get_block = FFI::Function.new(:int, %i[pointer ulong pointer ulong]) do |_param, position, out, size|\n        out.put_bytes(0, jpeg.byteslice(position, size) || ''.b)\n\n        1\n      end\n\n      file_access = Pdfium::FPDF_FILEACCESS.new\n      file_access[:m_FileLen] = jpeg.bytesize\n      file_access[:m_GetBlock] = get_block\n      file_access[:m_Param] = FFI::Pointer::NULL\n\n      pages_ptr = FFI::MemoryPointer.new(:pointer, 1)\n      pages_ptr.write_pointer(@page_ptr)\n\n      result = Pdfium.FPDFImageObj_LoadJpegFileInline(pages_ptr, 1, object_ptr, file_access)\n\n      raise PdfiumError, 'Failed to load redacted image' if result.zero?\n    end\n\n    def text_objects\n      return @text_objects if @text_objects\n\n      ensure_not_closed!\n\n      @text_objects = []\n\n      object_count = Pdfium.FPDFPage_CountObjects(page_ptr)\n\n      return @text_objects if object_count.zero?\n\n      text_page = Pdfium.FPDFText_LoadPage(page_ptr)\n\n      if text_page.null?\n        Pdfium.check_last_error(\"Failed to load text page #{page_index}\")\n","sourceCodeStart":1501,"sourceCodeEnd":1537,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/pdfium.rb#L1501-L1537","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Re-encode the redacted bitmap as a baseline (non-progressive) RGB JPEG in the block passed to redact_image_objects.","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.","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."],"exampleFix":"# before (block may return garbage/empty encode)\npage.redact_image_objects(rects) do |bitmap, pixel_rects|\n  RedactEncoder.to_jpeg(bitmap, pixel_rects)\nend\n\n# after (skip reload for undecodable encodes)\npage.redact_image_objects(rects) do |bitmap, pixel_rects|\n  jpeg = RedactEncoder.to_jpeg(bitmap, pixel_rects)\n  jpeg if jpeg.is_a?(String) && jpeg.bytesize > 4 && jpeg.getbyte(0) == 0xFF && jpeg.getbyte(1) == 0xD8\nend","handlingStrategy":"try-catch","validationCode":"# Validate the JPEG your redaction block produces before returning it\ndef redactable_jpeg?(jpeg)\n  jpeg.is_a?(String) &&\n    jpeg.bytesize > 4 &&\n    jpeg.getbyte(0) == 0xFF &&\n    jpeg.getbyte(1) == 0xD8 &&\n    jpeg.getbyte(-2) == 0xFF && # rough SOI/EOI sanity\n    jpeg.getbyte(-1) == 0xD9\nend","typeGuard":null,"tryCatchPattern":"begin\n  page.redact_image_objects(rects) { |bitmap, pixel_rects| encoder.call(bitmap, pixel_rects) }\nrescue Pdfium::PdfiumError => e\n  Rails.logger.warn(\"redaction skipped page #{page.page_index}: #{e.message}\")\n  page.draw_redaction_rects(rects) # opaque-rect fallback, content still covered\nend","preventionTips":["Encode redacted bitmaps as baseline RGB JPEG — avoid CMYK and progressive modes.","Never close, flatten, rotate or reload the page while redact_image_objects is iterating.","Keep the Pdfium::Document and its source buffer alive until every page operation finishes.","Run redaction on a single thread per document; PDFium FFI handles are not thread-safe."],"tags":["pdf","pdfium","ffi","image-redaction","jpeg"],"backgroundTag":"pdf-image-load-failed","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}