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

The combined size of the uploaded files exceeds the maximum

Error message

The combined size of the uploaded files exceeds the maximum allowed, even after compression. Please remove a file or upload smaller versions.

What it means

merge_within_size_budget first sums the sizes of all non-image (PDF) inputs — the only compressible pages are images, so a PDF set already over budget can never fit. If that incompressible_size alone exceeds max_size it raises FilesTooLargeError immediately, deliberately skipping the compression ladder, which would otherwise re-run the identical merge three times and still fail with an unearned 'even after compression' message.

Source

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

      downloaded_files = []
      blobs.each do |blob|
        tempfile = Tempfile.new(["dispute_evidence_input", File.extname(blob.filename.to_s)], binmode: true)
        downloaded_files << { tempfile:, content_type: blob.content_type }
        blob.download { |chunk| tempfile.write(chunk) }
        tempfile.flush
      end
      downloaded_files
    rescue StandardError
      downloaded_files.each { _1[:tempfile].close! }
      raise
    end

    def merge_within_size_budget(downloaded_files)
      # Only image pages can shrink, so a set of PDFs already over budget can never fit and
      # the ladder would just re-run the same merge three times with an unearned "even after
      # compression" message.
      incompressible_size = downloaded_files.sum { _1[:content_type].in?(IMAGE_CONTENT_TYPES) ? 0 : File.size(_1[:tempfile].path) }
      raise FilesTooLargeError, FILES_TOO_LARGE_MESSAGE if incompressible_size > max_size

      compressible = downloaded_files.any? { _1[:content_type].in?(IMAGE_CONTENT_TYPES) }
      compression_steps = compressible ? IMAGE_COMPRESSION_STEPS : IMAGE_COMPRESSION_STEPS.take(1)

      compression_steps.each do |compression|
        merged_path = merge(downloaded_files, compression)
        return merged_path if File.size(merged_path) <= max_size

        File.unlink(merged_path)
      end

      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)

View on GitHub (pinned to afeacbd394)

Solutions

  1. Remove one or more PDFs from the submission
  2. Re-export leaner PDFs (disable full-font embedding, lower embedded-image quality)
  3. Replace wall-of-text PDFs with a JPEG screenshot of the key exchange — images can be recompressed by the merge ladder

Example fix

# before
blobs = [pdf1, pdf2, pdf3, pdf4] # 8 MB of PDFs vs 5 MB budget
# => FilesTooLargeError: The combined size ... even after compression.

# after
blobs = [pdf1, pdf2] # 4 MB, plus a JPG of the key chat excerpt
Defensive patterns

Strategy: validation

Validate before calling

pdf_bytes = blobs.select { _1.content_type == 'application/pdf' }.sum(&:byte_size)
raise 'PDFs alone exceed the budget' if pdf_bytes > dispute_evidence.customer_communication_file_max_size

Type guard

def incompressible_pdf_bytes_within?(blobs, max_size)
  blobs.select { _1.content_type == 'application/pdf' }.sum(&:byte_size) <= max_size
end

Try / catch

begin
  DisputeEvidence::MergeCustomerCommunicationFilesService.perform(blobs:, max_size: budget)
rescue DisputeEvidence::MergeCustomerCommunicationFilesService::FilesTooLargeError => e
  redirect_back alert: e.message
end

Prevention

When it happens

Trigger: Submitting several PDFs whose combined bytes already exceed dispute_evidence.customer_communication_file_max_size, e.g. 4 × 2 MB PDF bank-statement exports against a ~5 MB remaining Stripe budget, with no images in the set at all.

Common situations: Chat logs and statements exported as multiple PDFs — PDFs are carried through verbatim by the merge, so their bytes are a hard floor.

Related errors


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