antiwork/gumroad · warning · ValidationError

Image must be at least 600x600px.

Error message

Image must be at least 600x600px.

What it means

Client-side pre-upload validation in Gumroad's product ThumbnailEditor. Before a selected file is handed to ActiveStorage direct upload, validateFile() decodes it in the browser and enforces, in order: allowed extension, size under 5 MB, decodable image, square aspect, and finally both sides >= 600px (MIN_SIDE_DIMENSION). This error is the last gate: the image is square but its height/width is below 600px, which would render blurry product cards and covers.

Source

Thrown at app/javascript/components/ProductEdit/ProductTab/ThumbnailEditor.tsx:41

const MEGABYTE = 1024 * 1024;
const MAX_FILE_SIZE = 5 * MEGABYTE;
export class ValidationError extends Error {
  constructor(message = "Invalid file type.") {
    super(message);
  }
}

const validateFile = async (file: File) => {
  if (!FileUtils.isFileNameExtensionAllowed(file.name, ALLOWED_EXTENSIONS)) throw new ValidationError();

  if (file.size > MAX_FILE_SIZE)
    throw new ValidationError("Could not process your thumbnail, please upload an image with size smaller than 5 MB.");

  const dimensions = await getImageDimensionsFromFile(file).catch(() => null);
  if (!dimensions) throw new ValidationError();
  if (dimensions.height !== dimensions.width) throw new ValidationError("Image must be square.");

  if (dimensions.height < MIN_SIDE_DIMENSION) throw new ValidationError("Image must be at least 600x600px.");
};

export const coverUrlForThumbnail = (covers: AssetPreview[]) =>
  covers.find((cover) => cover.type === "image" || cover.type === "unsplash")?.url ?? null;

export const ThumbnailEditor = ({
  covers,
  thumbnail,
  setThumbnail,
  permalink,
  nativeType,
}: {
  covers: AssetPreview[];
  thumbnail: Thumbnail | null;
  setThumbnail: (thumbnail: Thumbnail | null) => void;
  permalink: string;
  nativeType: ProductNativeType;
}) => {

View on GitHub (pinned to afeacbd394)

Solutions

  1. Re-export or resize the image to a square at least 600x600 (1024x1024 or larger recommended) and re-select it.
  2. If the file is HEIC or an unusual container, convert it to PNG/JPG first so the browser decodes its true dimensions.
  3. If you maintain this code and need a different floor, change MIN_SIDE_DIMENSION in ThumbnailEditor.tsx together with any server-side cover pipeline expectation.
  4. Confirm the file is a real image: an undecodable file throws the generic 'Invalid file type.' ValidationError instead, which has a different fix.

Example fix

# before: 512x512.png selected -> 'Image must be at least 600x600px.'
# after: resize to a >=600px square
magick icon_512.png -resize 1200x1200 icon_1200.png
Defensive patterns

Strategy: validation

Validate before calling

import { getImageDimensionsFromFile } from "$app/utils/image";

const MIN_SIDE = 600;
const thumbnailDimensionError = async (file: File): Promise<string | null> => {
  const dims = await getImageDimensionsFromFile(file).catch(() => null);
  if (!dims) return "Not a readable image.";
  if (dims.width !== dims.height) return "Image must be square.";
  if (dims.height < MIN_SIDE) return `Image must be at least ${MIN_SIDE}x${MIN_SIDE}px.`;
  return null;
};

Type guard

const isSquareAtLeast600 = (d: { width: number; height: number } | null): d is { width: number; height: number } =>
  !!d && d.width === d.height && d.height >= 600;

Try / catch

try {
  await validateFile(file);
} catch (e) {
  if (e instanceof ValidationError) {
    showAlert(e.message, "error"); // message is already user-facing
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A user picks a square raster image smaller than 600x600 (e.g. a 256x256 logo or 512x512 export) in the product thumbnail editor; getImageDimensionsFromFile resolves with height < 600 and validateFile throws ValidationError('Image must be at least 600x600px.') before any DirectUpload begins. Non-square images fail one line earlier with 'Image must be square.', so this exact message implies a square-but-small file.

Common situations: Small logo/avatar artwork exported at native size, low-DPI screenshots, icons or favicons reused as covers, and HEIC/EXIF-rotated files whose decoded dimensions differ from the OS preview. Also developers reusing ThumbnailEditor with a pipeline that downsizes images below 600px.

Related errors


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