antiwork/gumroad · warning · ValidationError
Invalid file type.
Error message
Invalid file type.
What it means
First check in validateFile for product thumbnails: FileUtils.isFileNameExtensionAllowed(file.name, ALLOWED_EXTENSIONS) rejects any file whose extension is not on the allowlist, throwing ValidationError with its default message 'Invalid file type.'. This is pure client-side gating before any upload — the file is judged by name extension only, not content.
Source
Thrown at app/javascript/components/ProductEdit/ProductTab/ThumbnailEditor.tsx:32
eager: true,
query: "?url",
import: "default",
});
const nativeTypeThumbnails = Object.fromEntries(
Object.entries(rawThumbnails).map(([key, value]) => [`./${key.split("/").pop()}`, value]),
);
const MIN_SIDE_DIMENSION = 600;
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,View on GitHub (pinned to afeacbd394)
Solutions
- Check ALLOWED_EXTENSIONS in ThumbnailEditor.tsx and export/convert the image to one of them (JPEG/PNG/WebP are the usual set).
- Re-save via an image editor or `sips`/ImageMagick: `magick input.tiff output.jpg`.
- If a legitimate format is being rejected, extend ALLOWED_EXTENSIONS and mirror any server-side validation.
- Set the file picker's accept attribute to the allowed MIME types so invalid files cannot be chosen in the first place.
Example fix
// before
<input type="file" onChange={handleFile} />
// after — the picker itself prevents picking a disallowed type
<input type="file" accept="image/jpeg,image/png,image/webp" onChange={handleFile} /> Defensive patterns
Strategy: validation
Validate before calling
const hasAllowedExtension = (file: File): boolean =>
FileUtils.isFileNameExtensionAllowed(file.name, ALLOWED_EXTENSIONS);
if (!hasAllowedExtension(file)) {
showAlert(`Supported formats: ${ALLOWED_EXTENSIONS.join(', ')}.`, 'error');
return;
} Type guard
const isValidationError = (e: unknown): e is ValidationError => e instanceof ValidationError;
Try / catch
try {
await validateFile(file);
} catch (e) {
if (e instanceof ValidationError) { showAlert(e.message, 'error'); return; } // user-input problem
throw e; // unexpected — let it propagate
} Prevention
- Set accept on the file input to the allowed MIME types so the OS picker filters before selection.
- Show the allowed extension list in the UI next to the picker — users should not discover the list by failing.
- Judge by extension AND content: renamed files pass the extension check but fail decode later.
- Keep the client ALLOWED_EXTENSIONS in sync with any server-side validation so both gates agree.
When it happens
Trigger: Uploading a thumbnail with an extension outside ALLOWED_EXTENSIONS (e.g. .tiff, .heic, .bmp, .pdf when only jpg/png/webp-style entries are allowed); double extensions like photo.jpg.exe; an extensionless filename from a screenshot or drag-and-drop tool.
Common situations: Designers exporting TIFF/HEIC from cameras and design tools; files saved without extensions; users renaming files to force acceptance (caught here); allowlist updated server-side but stale in the client bundle.
Related errors
- Could not process your thumbnail, please upload an image wit
- Image must be square.
- Image must be at least 600x600px.
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/437c8db6d49688c1.
Report an issue: GitHub.