{"record":{"id":"d0c88ef6ea944e40","repo":"RocketChat/Rocket.Chat","slug":"emoji-is-not-image","errorCode":"emoji-is-not-image","errorMessage":"Emoji file provided cannot be uploaded since it's not an image","messagePattern":"Emoji file provided cannot be uploaded since it's not an image","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/emoji-custom.ts","lineNumber":202,"sourceCode":"\t\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t\t},\n\t\t},\n\t\tasync function action() {\n\t\t\tconst emoji = await getUploadFormData(\n\t\t\t\t{\n\t\t\t\t\trequest: this.request,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfield: 'emoji',\n\t\t\t\t\tsizeLimit: settings.get('FileUpload_MaxFileSize'),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst { fields, fileBuffer, mimetype } = emoji;\n\n\t\t\tconst isUploadable = await Media.isImage(fileBuffer);\n\t\t\tif (!isUploadable) {\n\t\t\t\tthrow new Meteor.Error('emoji-is-not-image', \"Emoji file provided cannot be uploaded since it's not an image\");\n\t\t\t}\n\n\t\t\tconst [, extension] = mimetype.split('/');\n\t\t\tfields.extension = extension;\n\n\t\t\tconst emojiData = await insertOrUpdateEmoji(this.userId, {\n\t\t\t\t...fields,\n\t\t\t\tnewFile: true,\n\t\t\t\taliases: fields.aliases || '',\n\t\t\t\tname: fields.name,\n\t\t\t\textension: fields.extension,\n\t\t\t});\n\n\t\t\tawait uploadEmojiCustomWithBuffer(this.userId, fileBuffer, mimetype, emojiData);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t)","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/emoji-custom.ts#L184-L220","documentation":"Thrown by POST emoji-custom.create when Media.isImage(fileBuffer) returns false — the uploaded bytes are not a recognizable image. The endpoint reads the multipart 'emoji' field and inspects actual content, not the declared mimetype, so renaming a non-image file to .png will still fail.","triggerScenarios":"Uploading a text/PDF/JSON file renamed to .png; a corrupted or truncated image; a format Media.isImage does not accept; an empty buffer.","commonSituations":"Wrong file selected in the picker; asset exported as SVG with embedded non-image data; client skips preview validation; file truncated during upload.","solutions":["Upload a real raster image (PNG/JPEG/GIF/WebP).","Pre-validate client-side via file.type and/or magic-byte detection before POSTing.","Re-export the source asset as a standard image format."],"exampleFix":"// before\nconst fd = new FormData(); fd.append('emoji', file, file.name); // file may be a .svg\n// after\nconst allowed = ['image/png','image/jpeg','image/gif','image/webp'];\nif (!allowed.includes(file.type)) throw new Error('please choose a PNG/JPEG/GIF/WebP image');\nconst fd = new FormData(); fd.append('emoji', file, file.name);","handlingStrategy":"validation","validationCode":"const ALLOWED = ['image/png','image/jpeg','image/gif','image/webp'];\nif (!ALLOWED.includes(file.type)) throw new Error('emoji must be an image');","typeGuard":"function isImageFile(f): f is File {\n  return f instanceof File && f.type.startsWith('image/');\n}","tryCatchPattern":"try { await createEmojiCustom(fd); }\ncatch (e) {\n  if (isApiError(e, 'emoji-is-not-image')) { /* prompt user for a real image */) }\n  else throw e;\n}","preventionTips":["Restrict the file picker to image/* via the accept attribute.","Validate file.type and ideally magic bytes before upload.","Keep emojis as PNG/GIF/JPEG exports."],"tags":["emoji-custom","upload","validation","files","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}