{"record":{"id":"869816758ba35107","repo":"gitroomhq/postiz-app","slug":"unsupported-file-type-869816","errorCode":null,"errorMessage":"Unsupported file type.","messagePattern":"Unsupported file type\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"libraries/nestjs-libraries/src/upload/cloudflare.storage.ts","lineNumber":98,"sourceCode":"  async uploadSimple(path: string) {\n    const dataUrl = path.startsWith('data:') ? parseDataUrl(path) : null;\n\n    let body: Buffer;\n    if (dataUrl) {\n      body = dataUrl.buffer;\n    } else {\n      if (!(await isSafePublicHttpsUrl(path))) {\n        throw new Error('Unsafe URL');\n      }\n      const loadImage = await fetch(path, {\n        // @ts-ignore — undici option, not in lib.dom fetch types\n        dispatcher: ssrfSafeDispatcher,\n      });\n      body = Buffer.from(await loadImage.arrayBuffer());\n    }\n    const detected = await fileTypeFromBuffer(body);\n    if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) {\n      throw new Error('Unsupported file type.');\n    }\n    const extension = detected.ext;\n    const safeContentType = detected.mime;\n    const id = makeId(10);\n\n    const params = {\n      Bucket: this._bucketName,\n      Key: `${id}.${extension}`,\n      Body: body,\n      ContentType: safeContentType,\n      ChecksumMode: 'DISABLED',\n    };\n\n    const command = new PutObjectCommand({ ...params });\n    await this._client.send(command);\n\n    return `${this._uploadUrl}/${id}.${extension}`;\n  }","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts#L80-L116","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait storage.uploadSimple('https://example.com/photo.heic'); // throws Unsupported file type.\n\n// after — convert first, or validate before upload\nimport filetype from 'magic-bytes.js'; // or convert with sharp:\nimport sharp from 'sharp';\nconst jpeg = await sharp('photo.heic').jpeg().toBuffer();\nawait storage.uploadSimple(`data:image/jpeg;base64,${jpeg.toString('base64')}`);","handlingStrategy":"validation","validationCode":"import { fromBuffer } from 'file-type';\n\nconst detected = await fromBuffer(buffer);\nconst 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']);\nif (!detected || !ALLOWED.has(detected.mime)) {\n  throw new BadRequestException(`File type ${detected?.mime ?? 'unknown'} is not supported`);\n}","typeGuard":"async function isAllowedMediaBuffer(buf: Buffer): Promise<boolean> {\n  const t = await fromBuffer(buf);\n  return !!t && ALLOWED.has(t.mime);\n}","tryCatchPattern":"try {\n  await storage.uploadSimple(path);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Unsupported file type.') {\n    return res.status(415).send('Unsupported file type. Allowed: jpeg, png, gif, webp, avif, bmp, tiff, mp4, mpeg, wav, ogg');\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["file-type","upload","validation","mime","cloudflare-r2"],"backgroundTag":"unsupported-file-type","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}