{"record":{"id":"6ef7a67105868eab","repo":"antiwork/gumroad","slug":"that-file-is-too-large-images-can-be-up-to-max","errorCode":null,"errorMessage":"That file is too large. Images can be up to #{MAX_IMAGE_BYTES / 1.megabyte} MB.","messagePattern":"That file is too large\\. Images can be up to #(.+?) MB\\.","errorType":"exception","errorClass":"CreatePublicMediaService::RemoteFileTooLarge","httpStatus":null,"severity":"error","filePath":"app/services/create_public_media_service.rb","lineNumber":189,"sourceCode":"      blob\n    end\n\n    # Download the remote file to a tempfile with SSRF protection and a hard size ceiling, then\n    # store it as a blob. The size is enforced while streaming (both via the Content-Length header\n    # and by counting actual bytes) so a file larger than the 10 MB image cap is cut off\n    # mid-download instead of being fully downloaded (and uploaded to public storage) only to be\n    # rejected by the size check afterwards. Mirrors the hardened fetch the product thumbnail's\n    # URL path already uses (Thumbnail#url=).\n    def download_blob_from_url\n      normalized_url = normalize_url(url)\n      uri = URI.parse(normalized_url)\n      raise URI::InvalidURIError, \"URL '#{normalized_url}' is not a web url\" unless uri.scheme.in?(%w[http https])\n      raise URI::InvalidURIError, \"URL must include a valid host\" if uri.host.blank?\n\n      tempfile = Tempfile.new(binmode: true)\n      begin\n        response = SsrfFilter.get(normalized_url) do |http_response|\n          raise RemoteFileTooLarge if http_response[\"content-length\"].to_i > MAX_IMAGE_BYTES\n\n          write_file = http_response.is_a?(Net::HTTPSuccess)\n          received_bytes = 0\n          byte_limit = MAX_IMAGE_BYTES\n          http_response.read_body do |chunk|\n            received_bytes += chunk.bytesize\n            raise RemoteFileTooLarge if received_bytes > byte_limit\n\n            tempfile.write(chunk) if write_file\n          end\n        end\n        raise ActiveStorage::FileNotFoundError unless response.is_a?(Net::HTTPSuccess)\n\n        tempfile.rewind\n        # Sniff the real content type from the file bytes. The remote server's header is used only\n        # as a hint — a mislabeled or disguised file is classified by what it actually contains.\n        content_type = Marcel::MimeType.for(tempfile, name: filename_from(uri), declared_type: response.content_type)\n        tempfile.rewind","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/services/create_public_media_service.rb#L171-L207","documentation":"Before streaming any body bytes, download_blob_from_url compares the remote response's Content-Length header against MAX_IMAGE_BYTES (10 MB) and raises RemoteFileTooLarge; #process rescues it into this message. This is the fast path of the size ceiling: an oversized file is cut off before it is downloaded, instead of being fully fetched and uploaded to public storage only to be rejected afterwards.","triggerScenarios":"Passing url pointing at a file whose server advertises Content-Length greater than 10_485_760 bytes (e.g. a 32 MB PNG or a print-resolution export) to CreatePublicMediaService with only url set (no signed_blob_id).","commonSituations":"Sellers link high-resolution photos or unoptimized design-tool exports hosted on their own site or CDN; images large enough for print are routinely over 10 MB.","solutions":["Host and submit a web-sized version of the image (resize/compress until under 10 MB)","Use a CDN thumbnail parameter if available, e.g. '?w=2000' or '/_2000x/...' variants","Compress locally (e.g. 'convert in.png -resize 2000x -quality 85 out.jpg') and link that file","Or direct-upload the compressed file and pass signed_blob_id instead of url"],"exampleFix":"# before\nurl: 'https://cdn.example.com/brand-poster.png' # Content-Length: 32 MB\n# => failure: That file is too large. Images can be up to 10 MB.\n\n# after\nurl: 'https://cdn.example.com/brand-poster.png?w=2000&fm=jpg' # ~1 MB","handlingStrategy":"validation","validationCode":"MAX_IMAGE_BYTES = 10.megabytes\n\n# hint only: dynamic endpoints can lie or omit the header\nsize_hint = URI.open(url, 'r') { |f| f.meta['content-length']&.to_i }\nreturn if size_hint && size_hint <= MAX_IMAGE_BYTES\nraise 'file likely exceeds the 10 MB cap' if size_hint","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-shrink images to web dimensions (<= ~2000 px, JPEG ~85%) before hosting them for landing pages","The cap (CreatePublicMediaService::MAX_IMAGE_BYTES = 10.megabytes) applies to both the url and signed_blob_id paths","Treat Result(success: false, error_message: 'That file is too large...') as user-facing copy and show it directly"],"tags":["ruby","rails","file-size","http-download","active-storage"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}