toeverything/AFFiNE · error · ImageFormatNotSupported
image_format_not_supported
image_format_not_supported
Error message
Image format not supported: ${format} What it means
Thrown while processing an uploaded image attachment: the buffer's detected MIME type starts with 'image/', but processImage (resize to COPILOT_IMAGE_MAX_EDGE, convert to webp) rejected or crashed on the bytes. It wraps the failure as ImageFormatNotSupported with error code 'image_format_not_supported', naming the detected MIME in {format}. Typical causes are corrupted payloads, CMYJ/EXIF-heavy JPEGs, or exotic formats that the decoder cannot handle even though sniffing labeled them image/*.
Solutions
- Re-encode the image client-side to standard JPEG/PNG/WebP before upload
- Verify the file opens in an image viewer and is not truncated (check byte size > 0 and matches source)
- Retry the upload — transient read/truncation during transfer can corrupt the buffer
- If maintaining this code: narrow the catch to decoder-specific errors and let unexpected failures surface separately
Example fix
// before
await inbox.createMessage(userId, { sessionId, blob: corruptedBuffer });
// after
try {
const webp = await processImage(buffer, maxEdge, true);
await inbox.createMessage(userId, { sessionId, blob: webp, blobMimeType: 'image/webp' });
} catch {
showUserError('This image format is not supported. Please use PNG, JPEG or WebP.');
} Defensive patterns
Strategy: validation
Validate before calling
const sniffed = await imageType(buffer); // e.g. file-type
const SUPPORTED = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
if (!sniffed || !SUPPORTED.includes(sniffed.mime)) {
return rejectUpload('Use PNG, JPEG, WebP or GIF');
}
const probe = await loadImage(buffer); // throws on truncated/unsupported bytes
if (buffer.length === 0) return rejectUpload('Empty file'); Type guard
const isDecodableImage = async (buf: Buffer): Promise<boolean> => {
try { await sharp(buf).metadata(); return true; } catch { return false; }
}; Try / catch
try {
await inbox.createMessage(userId, { sessionId, blob });
} catch (e) {
if (e.code === 'image_format_not_supported') {
notifyUser(`Unsupported image format: ${e.format ?? 'unknown'}. Re-encode as PNG/JPEG/WebP.`);
} else throw e;
} Prevention
- Client-side pre-encode uploads to a standard format and verify decodability before sending
- Check file size > 0 and matches the source after any transfer/compression step
- Surface the reported {format} to the user so they know which file failed
When it happens
Trigger: Uploading a truncated or corrupted image file; an image whose extension/sniffed MIME says image/* but whose codec is unsupported (e.g. HEIC mislabeled, TIFF with odd compression, 16-bit PNG edge cases); a zero-byte or text file renamed to .png so the sniffer misclassifies it.
Common situations: Paste/drag from clipboard produces partial buffer; client-side compression library emits nonstandard webp/jpeg; users rename files to bypass type checks.
Related errors
- blob_invalid
- blob_quota_exceeded
- copilot_failed_to_add_workspace_artifact
- copilot_prompt_invalid
- copilot_session_invalid_input
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/c854f2eca5bdd7c2.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/plugins/copilot/conversation/inbox.ts:85
for (const blob of blobs) {
const uploaded = await this.storage.handleUpload(blob);
const detectedMime =
sniffMime(uploaded.buffer, blob.mimetype)?.toLowerCase() ||
blob.mimetype;
let attachmentBuffer = uploaded.buffer;
let attachmentMimeType = detectedMime;
if (detectedMime.startsWith('image/')) {
try {
attachmentBuffer = await processImage(
uploaded.buffer,
COPILOT_IMAGE_MAX_EDGE,
true
);
attachmentMimeType = 'image/webp';
} catch {
throw new ImageFormatNotSupported({ format: detectedMime });
}
}
const filename = createHash('sha256')
.update(attachmentBuffer)
.digest('base64url');
const terminalMode = await this.access.sessionResource(
{
userId,
workspaceId: session.config.workspaceId,
docId: session.config.docId,
action: session.config.docId ? 'Doc.Update' : 'Workspace.Copilot',
},
[options.sessionId]
);
if (terminalMode !== 'canonical') {
throw new BadRequestException(
"Local workspaces don't support attachments or references."View on GitHub (pinned to 2af30773ae)