toeverything/AFFiNE · error · ImageFormatNotSupported
image_format_not_supported
image_format_not_supported
Error message
Image format not supported: ${format} What it means
Avatar uploads sniff the file's magic bytes, cross-checking the declared mimetype. If sniffing cannot identify a type at all, or the identified type does not start with 'image/', the upload is rejected with image_format_not_supported ('unknown' when sniffing failed) before any image processing runs.
Solutions
- Upload actual raster images (png/jpeg/webp/gif)
- Validate the file type client-side (extension + magic bytes) before starting the upload
- Convert exotic formats to png/webp before uploading
Example fix
// before
await uploadAvatar(file); // pdf renamed to .png -> image_format_not_supported
// after
if (!file.type.startsWith('image/')) throw new Error('pick an image file');
await uploadAvatar(file); Defensive patterns
Strategy: validation
Validate before calling
// client-side gate before upload
if (!file.type.startsWith('image/')) {
throw new Error('please choose an image file');
}
if (file.size > 5 * 1024 * 1024) {
throw new Error('image must be under 5MB');
} Type guard
function isImageFile(file: File): boolean {
return file.type.startsWith('image/');
} Try / catch
try {
await uploadAvatar(file);
} catch (e) {
if (e?.extensions?.code === 'IMAGE_FORMAT_NOT_SUPPORTED') showFormatError();
else throw e;
} Prevention
- Accept only image/* in the file picker (accept attribute) and re-check the type in code
- Remember the server sniffs magic bytes, so renaming extensions will not pass
- Convert spreadsheets/screenshots-in-pdf etc. to real images before upload
When it happens
Trigger: Uploading a non-image (pdf, zip, text) renamed to .png; an empty or truncated file whose bytes cannot be sniffed; formats the sniffer does not recognize.
Common situations: Automated imports feeding arbitrary files; drag-and-drop grabbing the wrong file; mislabeled files produced by other tooling.
Related errors
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/87891d5ba5135d55.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/user/resolver.ts:130
name: 'uploadAvatar',
description: 'Upload user avatar',
})
async uploadAvatar(
@CurrentUser() user: CurrentUser,
@Args({ name: 'avatar', type: () => GraphQLUpload })
avatar: FileUpload
) {
if (!user) {
throw new UserNotFound();
}
const avatarBuffer = await readBufferWithLimit(
avatar.createReadStream(),
5 * OneMB
);
const contentType = sniffMime(avatarBuffer, avatar.mimetype)?.toLowerCase();
if (!contentType || !contentType.startsWith('image/')) {
throw new ImageFormatNotSupported({ format: contentType || 'unknown' });
}
let processedAvatarBuffer: Buffer;
try {
processedAvatarBuffer = await processImage(avatarBuffer, 512, false);
} catch {
throw new ImageFormatNotSupported({ format: contentType });
}
const avatarUrl = await this.storage.put(
`${user.id}-avatar-${Date.now()}`,
processedAvatarBuffer,
{ contentType: 'image/webp' }
);
if (user.avatarUrl) {
await this.storage.delete(user.avatarUrl);
}View on GitHub (pinned to 2af30773ae)