toeverything/AFFiNE · warning · ImageFormatNotSupported
image_format_not_supported
image_format_not_supported
Error message
Image format not supported: ${format} What it means
Thrown by the uploadAvatar mutation when sniffMime() cannot identify the uploaded buffer's MIME type, or when the detected type does not start with 'image/'. This is the first image validation gate, run against the raw bytes (the declared mimetype is only a fallback hint for sniffing). Non-image uploads are rejected before any processing.
Source
Thrown at packages/backend/server/src/core/user/resolver.ts:128
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 26c515e050)
Solutions
- Validate the file type on the client before uploading (accept='image/*' and check the actual type).
- Ensure the upload is not truncated by body-size limits in the proxy/gateway.
- If SVG should be allowed, confirm sniffMime/processImage support it; otherwise restrict the picker to raster formats.
Example fix
// before <input type="file" /> // after <input type="file" accept="image/png,image/jpeg,image/webp,image/gif" />
Defensive patterns
Strategy: validation
Validate before calling
const type = await sniffType(file);
if (!type.startsWith('image/')) { alert('Please choose an image file.'); return; } Type guard
function isImageType(type?: string | null): boolean {
return Boolean(type && type.startsWith('image/'));
} Try / catch
try {
await uploadAvatar(file);
} catch (e) {
if (e?.code === 'image_format_not_supported') { showFormatError(); return; }
throw e;
} Prevention
- Use <input accept="image/*"> and validate the sniffed type client-side.
- Reject non-image files before the network round-trip.
- Watch for truncated uploads caused by body-size limits.
When it happens
Trigger: Client uploads a file whose magic bytes are not a recognized image format, or whose sniffed type is application/pdf, text/*, etc. Also fires when the buffer is empty or truncated so sniffing fails.
Common situations: User selects a PDF, SVG (if not sniffed as image), or text file instead of a photo; upload truncated by a proxy limit; client declares image/png but sends unrelated bytes.
Related errors
- Failed to read image size
- action_forbidden
- user_avatar_not_found
- user_not_found
- ErrorCode.DefaultRuntimeError
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/87891d5ba5135d55.
Report an issue: GitHub.