gitroomhq/postiz-app · error · Error
Unsupported file type.
Error message
Unsupported file type.
What it means
Thrown by CloudflareStorage.uploadSimple when the fetched/uploaded buffer's magic-byte sniffing (file-type's fileTypeFromBuffer) fails or produces a MIME type not in ALLOWED_MIME_TYPES (jpeg, png, gif, webp, avif, bmp, tiff, mp4 video, mpeg/mp4/wav/ogg audio). Content is detected from bytes, not from file extension or Content-Type header, so mislabeled files are rejected.
Source
Thrown at libraries/nestjs-libraries/src/upload/cloudflare.storage.ts:98
async uploadSimple(path: string) {
const dataUrl = path.startsWith('data:') ? parseDataUrl(path) : null;
let body: Buffer;
if (dataUrl) {
body = dataUrl.buffer;
} else {
if (!(await isSafePublicHttpsUrl(path))) {
throw new Error('Unsafe URL');
}
const loadImage = await fetch(path, {
// @ts-ignore — undici option, not in lib.dom fetch types
dispatcher: ssrfSafeDispatcher,
});
body = Buffer.from(await loadImage.arrayBuffer());
}
const detected = await fileTypeFromBuffer(body);
if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) {
throw new Error('Unsupported file type.');
}
const extension = detected.ext;
const safeContentType = detected.mime;
const id = makeId(10);
const params = {
Bucket: this._bucketName,
Key: `${id}.${extension}`,
Body: body,
ContentType: safeContentType,
ChecksumMode: 'DISABLED',
};
const command = new PutObjectCommand({ ...params });
await this._client.send(command);
return `${this._uploadUrl}/${id}.${extension}`;
}View on GitHub (pinned to 0f1647f749)
Solutions
- Convert the asset to an allowed type before upload (e.g. HEIC→jpeg, mov→mp4, svg→png)
- If fetching a remote URL, verify it actually returns the media bytes (curl -I) and not an HTML page
- Extend ALLOWED_MIME_TYPES only after reviewing security implications (SVG especially enables XSS)
- Check the buffer is non-empty and not corrupted before calling uploadSimple
Example fix
// before
await storage.uploadSimple('https://example.com/photo.heic'); // throws Unsupported file type.
// after — convert first, or validate before upload
import filetype from 'magic-bytes.js'; // or convert with sharp:
import sharp from 'sharp';
const jpeg = await sharp('photo.heic').jpeg().toBuffer();
await storage.uploadSimple(`data:image/jpeg;base64,${jpeg.toString('base64')}`); Defensive patterns
Strategy: validation
Validate before calling
import { fromBuffer } from 'file-type';
const detected = await fromBuffer(buffer);
const ALLOWED = new Set(['image/jpeg','image/png','image/gif','image/webp','image/avif','image/bmp','image/tiff','video/mp4','audio/mpeg','audio/mp4','audio/wav','audio/ogg']);
if (!detected || !ALLOWED.has(detected.mime)) {
throw new BadRequestException(`File type ${detected?.mime ?? 'unknown'} is not supported`);
} Type guard
async function isAllowedMediaBuffer(buf: Buffer): Promise<boolean> {
const t = await fromBuffer(buf);
return !!t && ALLOWED.has(t.mime);
} Try / catch
try {
await storage.uploadSimple(path);
} catch (e) {
if (e instanceof Error && e.message === 'Unsupported file type.') {
return res.status(415).send('Unsupported file type. Allowed: jpeg, png, gif, webp, avif, bmp, tiff, mp4, mpeg, wav, ogg');
}
throw e;
} Prevention
- Reject unsupported types client-side (accept attribute + extension check) but always re-verify server-side via magic bytes
- Convert HEIC/mov/svg uploads to allowed formats before upload
- When fetching remote URLs, check the response Content-Type starts with image/ or video/ before passing to uploadSimple
When it happens
Trigger: Uploading an SVG, PDF, HEIC, text file, or any format outside the allowlist; uploading an HTML error page returned instead of an image because the URL returned 200 with a soft error; an empty/corrupt buffer; a data: URL whose base64 decodes to an unsupported type.
Common situations: Users uploading iPhone HEIC photos, SVGs, PDFs, or .mov/.webm videos; a remote URL returning an HTML login/captcha page that is fetched as the 'image'; truncated uploads producing undetectable buffers.
Related errors
- Unsupported file type.
- Unsupported file type.
- File is too large.
- All media must be uploaded through our upload API route and
- Unsafe URL
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/869816758ba35107.
Report an issue: GitHub.