{"record":{"id":"1d14a4233c988a18","repo":"docusealco/docuseal","slug":"failed-to-unwrap-form-object","errorCode":null,"errorMessage":"Failed to unwrap form object","messagePattern":"Failed to unwrap form object","errorType":"exception","errorClass":"Pdfium::PdfiumError","httpStatus":null,"severity":"error","filePath":"lib/pdfium.rb","lineNumber":1256,"sourceCode":"        form_ptr = find_form_object(rect_bounds)\n\n        break if form_ptr.nil?\n\n        unwrapped = true\n\n        matrix =\n          if Pdfium.FPDFPageObj_GetMatrix(form_ptr, matrix_ptr).zero?\n            [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]\n          else\n            matrix_ptr.read_array_of_float(6)\n          end\n\n        (Pdfium.FPDFFormObj_CountObjects(form_ptr) - 1).downto(0) do |index|\n          child_ptr = Pdfium.FPDFFormObj_GetObject(form_ptr, index)\n\n          next if child_ptr.null?\n\n          raise PdfiumError, 'Failed to unwrap form object' if Pdfium.FPDFFormObj_RemoveObject(form_ptr,\n                                                                                               child_ptr).zero?\n\n          Pdfium.FPDFPageObj_Transform(child_ptr, *matrix)\n          Pdfium.FPDFPage_InsertObject(@page_ptr, child_ptr)\n        end\n\n        remove_page_object(form_ptr)\n      end\n\n      Pdfium.FPDFPage_GenerateContent(@page_ptr) if unwrapped\n\n      reset_memoization if unwrapped\n    end\n\n    def find_form_object(rect_bounds = nil)\n      bounds_ptrs = Array.new(4) { FFI::MemoryPointer.new(:float) }\n\n      Pdfium.FPDFPage_CountObjects(@page_ptr).times do |index|","sourceCodeStart":1238,"sourceCodeEnd":1274,"githubUrl":"https://github.com/docusealco/docuseal/blob/004a22c1c88109c7ba0b567df011a8cb13894001/lib/pdfium.rb#L1238-L1274","documentation":"Raised in Page#unwrap_form_objects when FPDFFormObj_RemoveObject returns 0 while detaching a child object from a form object during redact or flatten. There is no check_last_error; the zero return means pdfium refused the removal, typically for malformed or deeply nested form XObject trees. The loop retries until no intersecting form object remains, so this fires on structural edge cases rather than ordinary AcroForm flattening.","triggerScenarios":"redact on pages containing nested form XObjects (forms inside forms), XFA remnants, or form objects with broken internal object arrays; PDFs from generators that wrap content in unusual XObject nesting.","commonSituations":"Flattening and redacting government/tax forms; PDFs printed through virtual printers that wrap page content in form XObjects.","solutions":["Catch per page and fall back to draw-only redaction (opaque rects without form unwrapping)","Update libpdfium; the form-object APIs gained robustness across releases","Pre-flatten the PDF with another tool (ghostscript) and then redact","In batch pipelines, skip and report the page for manual redaction"],"exampleFix":"# before\npage.redact(rects)\n\n# after\nbegin\n  page.redact(rects)\nrescue Pdfium::PdfiumError => e\n  raise unless e.message == 'Failed to unwrap form object'\n  page.draw_only_redact(rects) # fallback: paint rects, skip unwrapping\nend","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  page.redact(rects)\nrescue Pdfium::PdfiumError => e\n  raise unless e.message == 'Failed to unwrap form object'\n  page_redact_draw_only(page, rects) # opaque rects without form flattening\nend","preventionTips":["Keep a draw-only redaction fallback for structurally odd PDFs (nested form XObjects)","Ghostscript-flatten exotic PDFs before redaction","Track per-producer failure rates; forms from certain generators are repeat offenders"],"tags":["pdfium","redaction","form-flattening","pdf-objects","ruby"],"backgroundTag":"pdf-object-manipulation-failed","analyzedSha":"004a22c1c88109c7ba0b567df011a8cb13894001","analyzedAt":"2026-08-21T13:38:23.343Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}