{"record":{"id":"0dc57c0a41375ec5","repo":"antiwork/gumroad","slug":"could-not-process-your-thumbnail-please-upload-an","errorCode":null,"errorMessage":"Could not process your thumbnail, please upload an image with size smaller than 5 MB.","messagePattern":"Could not process your thumbnail, please upload an image with size smaller than 5 MB\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"warning","filePath":"app/javascript/components/ProductEdit/ProductTab/ThumbnailEditor.tsx","lineNumber":35,"sourceCode":"});\nconst nativeTypeThumbnails = Object.fromEntries(\n  Object.entries(rawThumbnails).map(([key, value]) => [`./${key.split(\"/\").pop()}`, value]),\n);\n\nconst MIN_SIDE_DIMENSION = 600;\nconst MEGABYTE = 1024 * 1024;\nconst MAX_FILE_SIZE = 5 * MEGABYTE;\nexport class ValidationError extends Error {\n  constructor(message = \"Invalid file type.\") {\n    super(message);\n  }\n}\n\nconst validateFile = async (file: File) => {\n  if (!FileUtils.isFileNameExtensionAllowed(file.name, ALLOWED_EXTENSIONS)) throw new ValidationError();\n\n  if (file.size > MAX_FILE_SIZE)\n    throw new ValidationError(\"Could not process your thumbnail, please upload an image with size smaller than 5 MB.\");\n\n  const dimensions = await getImageDimensionsFromFile(file).catch(() => null);\n  if (!dimensions) throw new ValidationError();\n  if (dimensions.height !== dimensions.width) throw new ValidationError(\"Image must be square.\");\n\n  if (dimensions.height < MIN_SIDE_DIMENSION) throw new ValidationError(\"Image must be at least 600x600px.\");\n};\n\nexport const coverUrlForThumbnail = (covers: AssetPreview[]) =>\n  covers.find((cover) => cover.type === \"image\" || cover.type === \"unsplash\")?.url ?? null;\n\nexport const ThumbnailEditor = ({\n  covers,\n  thumbnail,\n  setThumbnail,\n  permalink,\n  nativeType,\n}: {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/components/ProductEdit/ProductTab/ThumbnailEditor.tsx#L17-L53","documentation":"Second check in validateFile: file.size > 5 * 1024 * 1024 throws ValidationError('Could not process your thumbnail, please upload an image with size smaller than 5 MB.'). A hard client-side cap on thumbnail uploads — enforced before any network traffic, using the File object's byte size.","triggerScenarios":"Selecting any thumbnail over 5 MB — typical for unedited phone photos (12–48 MP HEIC/JPEG), print-resolution PNGs, or images exported at max quality from design tools.","commonSituations":"iPhone/Android default camera output; designers dropping 300-DPI print assets into a web product form; screenshots of retina displays saved as lossless PNG.","solutions":["Compress or resize below 5 MB — thumbnails render small, so 1200x1200 JPEG at ~80% quality is ample and typically well under 500 KB.","Re-export from the source tool at web resolution.","Automate with ImageMagick: `magick input.jpg -resize 1200x1200 -quality 80 thumb.jpg`.","Check size in the picker's onChange and warn before the user reaches submit (see defense)."],"exampleFix":"// before — user only learns at validation time\nconst handleFile = (file: File) => setThumbnail(file);\n\n// after — fail fast with the exact limit in the picker\nconst handleFile = (file: File) => {\n  if (file.size > 5 * 1024 * 1024) {\n    showAlert('Please choose an image smaller than 5 MB.', 'error');\n    return;\n  }\n  setThumbnail(file);\n};","handlingStrategy":"validation","validationCode":"const MAX_FILE_SIZE = 5 * 1024 * 1024;\nconst isWithinSizeLimit = (file: File): boolean => file.size <= MAX_FILE_SIZE;\n\nif (!isWithinSizeLimit(file)) {\n  showAlert('Please choose an image smaller than 5 MB.', 'error');\n  return;\n}","typeGuard":"const isValidationError = (e: unknown): e is ValidationError => e instanceof ValidationError;","tryCatchPattern":"try {\n  await validateFile(file);\n} catch (e) {\n  if (e instanceof ValidationError) { showAlert(e.message, 'error'); return; }\n  throw e;\n}","preventionTips":["Check file.size in the picker's onChange and reject early with the exact limit stated.","Downscale at selection time via canvas when the image is huge — thumbnails never need full resolution.","State the limit in the UI next to the upload control, not only in the error.","Remember File.size is bytes: 5 MB here is 5 * 1024 * 1024, not 5,000,000."],"tags":["file-validation","thumbnail","file-size","client-side"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}