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
- Re-export or resize the image to a square at least 600x600 (1024x1024 or larger recommended) and re-select it.
- If the file is HEIC or an unusual container, convert it to PNG/JPG first so the browser decodes its true dimensions.
- 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.
- 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
- Export thumbnails at 1024x1024 or larger so future floor increases are covered.
- Run dimension validation on file select, not on submit, so feedback is immediate.
- Keep MIN_SIDE_DIMENSION and the server-side cover pipeline requirements in sync when changing the floor.
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
- ${responseData.error}
- Something went wrong.
- Invalid file type.
- Could not process your thumbnail, please upload an image wit
- Image must be square.
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/82abe3eeb3bf3e22.
Report an issue: GitHub.