antiwork/gumroad · error · DisputeEvidence::MergeCustomerCommunicationFilesService::MergeError
One of the uploaded files is not a JPG, PNG, or PDF.
Error message
One of the uploaded files is not a JPG, PNG, or PDF.
What it means
Every input blob's content_type must be in DisputeEvidence::ALLOWED_FILE_CONTENT_TYPES (image/jpeg, image/png, application/pdf) or MergeError is raised. Because the merged output is always application/pdf, the model-level content-type validation never inspects the raw inputs — this explicit check is the only gate before seller-supplied bytes reach ImageMagick and qpdf.
Source
Thrown at app/services/dispute_evidence/merge_customer_communication_files_service.rb:50
def self.perform(blobs:, max_size:)
new(blobs:, max_size:).perform
end
def initialize(blobs:, max_size:)
@blobs = blobs
@max_size = max_size
end
# Returns a new application/pdf ActiveStorage::Blob. The input blobs are left alone: the
# caller purges them once the submission has actually been persisted.
def perform
if blobs.size > DisputeEvidence::MAX_CUSTOMER_COMMUNICATION_FILES
raise MergeError, "You can attach up to #{DisputeEvidence::MAX_CUSTOMER_COMMUNICATION_FILES} files."
end
# The merged output is always application/pdf, so the model's content-type validation never
# sees the inputs. Everything below hands seller-supplied bytes to ImageMagick and qpdf.
unless blobs.all? { _1.content_type.in?(DisputeEvidence::ALLOWED_FILE_CONTENT_TYPES) }
raise MergeError, UNSUPPORTED_FILE_TYPE_MESSAGE
end
raise FilesTooLargeError, FILE_TOO_LARGE_MESSAGE if blobs.any? { _1.byte_size > max_size }
downloaded_files = download_blobs
merged_path = merge_within_size_budget(downloaded_files)
File.open(merged_path) do |file|
ActiveStorage::Blob.create_and_upload!(io: file, filename: MERGED_FILENAME, content_type: "application/pdf")
end
ensure
downloaded_files&.each { _1[:tempfile].close! }
File.unlink(merged_path) if merged_path && File.exist?(merged_path)
end
private
attr_reader :blobs, :max_size
def download_blobsView on GitHub (pinned to afeacbd394)
Solutions
- Convert HEIC/WEBP/GIF/TIFF to plain JPG or PNG with a real converter before uploading
- Re-export documents as PDF
- If a previously saved attachment is the offender, remove it and submit a converted version
Example fix
# before # photo.HEIC uploaded directly from iPhone Photos MergeCustomerCommunicationFilesService.perform(blobs: [heic_blob], max_size: budget) # => MergeError: One of the uploaded files is not a JPG, PNG, or PDF. # after # 'sips -s format jpeg photo.HEIC --out photo.jpg' (macOS) or any converter, then upload
Defensive patterns
Strategy: validation
Validate before calling
unless blobs.all? { _1.content_type.in?(DisputeEvidence::ALLOWED_FILE_CONTENT_TYPES) }
raise 'only JPG, PNG and PDF are accepted'
end Type guard
def all_customer_communication_files_allowed?(blobs)
blobs.all? { _1.content_type.in?(DisputeEvidence::ALLOWED_FILE_CONTENT_TYPES) }
end Try / catch
begin DisputeEvidence::MergeCustomerCommunicationFilesService.perform(blobs:, max_size: budget) rescue DisputeEvidence::MergeCustomerCommunicationFilesService::MergeError => e redirect_back alert: e.message end
Prevention
- Set accept='.jpg,.jpeg,.png,.application/pdf' on the upload input so the picker filters most cases
- Convert HEIC/WEBP at the client or server edge; never rely on file extensions — ActiveStorage records the declared content type
- Remember the existing attached blob is re-validated on every later save
When it happens
Trigger: Attaching a HEIC photo (iPhone default for 'Photos' exports), a WEBP screenshot (many modern capture tools), GIF, TIFF, or any file whose recorded ActiveStorage content_type is outside the allowlist. The previously attached blob also counts as an input, so an older disallowed attachment re-triggers it on a later save.
Common situations: iPhone photos dragged out of the Photos app stay HEIC; screenshot/browser tools increasingly emit WEBP; files renamed '.jpg' without conversion keep their original recorded content type.
Related errors
- You can attach up to #{DisputeEvidence::MAX_CUSTOMER_COMMUNI
- One of the uploaded files exceeds the maximum size allowed.
- The combined size of the uploaded files exceeds the maximum
- One of the uploaded files could not be processed. Please che
- You must connect at least one payment method before you can
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/c2147b9ca302eea3.
Report an issue: GitHub.