antiwork/gumroad · error · DisputeEvidence::MergeCustomerCommunicationFilesService::MergeError

One of the uploaded files could not be processed. Please che

Error message

One of the uploaded files could not be processed. Please check that every PDF opens correctly and is not password-protected.

What it means

merge() shells out via Open3.capture3('qpdf', '--empty', '--pages', *page_paths, '--', merged_path); an exit status outside QPDF_SUCCESS_EXIT_CODES logs qpdf's stderr and raises MergeError with UNPROCESSABLE_FILE_MESSAGE. Typical qpdf failures are password-protected/encrypted input PDFs and malformed or corrupt PDF structure — qpdf cannot copy pages it cannot decrypt or parse.

Source

Thrown at app/services/dispute_evidence/merge_customer_communication_files_service.rb:117

      raise FilesTooLargeError, FILES_TOO_LARGE_MESSAGE
    end

    def merge(downloaded_files, compression)
      page_paths = []
      downloaded_files.each do |downloaded_file|
        if downloaded_file[:content_type].in?(IMAGE_CONTENT_TYPES)
          page_paths << image_to_pdf_page(downloaded_file[:tempfile].path, compression)
        else
          page_paths << downloaded_file[:tempfile].path
        end
      end

      merged_path = "#{Dir.tmpdir}/dispute_evidence_merged_#{SecureRandom.hex}.pdf"
      _stdout, stderr, status = Open3.capture3("qpdf", "--empty", "--pages", *page_paths, "--", merged_path)
      unless QPDF_SUCCESS_EXIT_CODES.include?(status.exitstatus)
        Rails.logger.error("[#{self.class.name}] qpdf failed: #{stderr}")
        File.unlink(merged_path) if File.exist?(merged_path)
        raise MergeError, UNPROCESSABLE_FILE_MESSAGE
      end

      merged_path
    ensure
      (page_paths - downloaded_files.map { _1[:tempfile].path }).each do |generated_path|
        File.unlink(generated_path) if File.exist?(generated_path)
      end
    end

    # Recompressing through JPEG also sidesteps the PNG variants (16-bit depth, interlaced)
    # that both Stripe and Prawn reject — see
    # Purchases::DisputeEvidenceController#covert_and_optimize_blob_if_needed.
    def image_to_pdf_page(image_path, compression)
      image = MiniMagick::Image.open(image_path)
      image.auto_orient
      image.resize("#{compression[:max_dimension]}x#{compression[:max_dimension]}>") if compression[:max_dimension]
      image.format("jpg")
      image.quality(compression[:quality]).colorspace("sRGB").strip

View on GitHub (pinned to afeacbd394)

Solutions

  1. Open every submitted PDF locally and confirm it loads without a password prompt
  2. Re-export/print-to-PDF the encrypted document without a password, then re-upload
  3. Re-download or regenerate the corrupt file and submit again
  4. If you operate the app, check the logged '[...MergeCustomerCommunicationFilesService] qpdf failed:' stderr for the exact qpdf diagnostic

Example fix

# before
blobs = [encrypted_statement_pdf, chat_jpg] # qpdf: 'file is encrypted'
# => MergeError: One of the uploaded files could not be processed...

# after
# print-to-PDF the statement without encryption -> statement.pdf
blobs = [statement_pdf, chat_jpg]
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-flight each PDF the same way the merge does
Open3.capture3('qpdf', '--show-encryption', pdf_path).then do |_out, _err, status|
  raise 'password-protected or unreadable PDF' unless status.success? # exit 0 = unencrypted, parseable
end

Try / catch

begin
  DisputeEvidence::MergeCustomerCommunicationFilesService.perform(blobs:, max_size: budget)
rescue DisputeEvidence::MergeCustomerCommunicationFilesService::MergeError => e
  # e.message is already seller-safe; the real qpdf stderr is in the Rails log
  Rails.logger.warn("merge rejected: #{e.message}")
  redirect_back alert: e.message
end

Prevention

When it happens

Trigger: One of the inputs is a password-protected bank statement or an owner-encrypted PDF; a PDF truncated during download; a zero-byte or fake .pdf (e.g. an HTML error page renamed to .pdf).

Common situations: Financial documents that ship with owner passwords; files corrupted in transit; exports from buggy third-party tools that produce non-conforming PDFs.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/823d55b860420f15. Report an issue: GitHub.