{"record":{"id":"309a2e8fd9de79c3","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-file-uploaded","errorCode":"error-invalid-file-uploaded","errorMessage":"Invalid file uploaded","messagePattern":"Invalid file uploaded","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/sms.ts","lineNumber":40,"sourceCode":"import type { ILivechatMessage } from '../../../lib/omnichannel/localTypes';\nimport { sendMessage } from '../../../lib/omnichannel/messages';\nimport { createRoom } from '../../../lib/omnichannel/rooms';\nimport { settings } from '../../../settings';\n\nconst logger = new Logger('SMS');\n\nconst getUploadFile = async (details: Omit<IUpload, '_id' | '_updatedAt'>, fileUrl: string) => {\n\tconst response = await fetch(fileUrl, {\n\t\tignoreSsrfValidation: false,\n\t\tallowList: settings.get<string>('SSRF_Allowlist'),\n\t});\n\n\tconst content = Buffer.from(await response.arrayBuffer());\n\n\tconst contentSize = content.length;\n\n\tif (response.status !== 200 || contentSize === 0) {\n\t\tthrow new Meteor.Error('error-invalid-file-uploaded', 'Invalid file uploaded');\n\t}\n\n\tconst fileStore = FileUpload.getStore('Uploads');\n\n\treturn fileStore.insert({ ...details, size: contentSize }, content);\n};\n\nconst defineDepartment = async (idOrName?: string) => {\n\tif (!idOrName || idOrName === '') {\n\t\treturn;\n\t}\n\n\tconst department = await LivechatDepartment.findOneByIdOrName(idOrName, { projection: { _id: 1 } });\n\treturn department?._id;\n};\n\nconst defineVisitor = async (smsNumber: string, targetDepartment?: string) => {\n\tconst visitor = await LivechatVisitors.findOneVisitorByPhone(smsNumber);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/sms.ts#L22-L58","documentation":"Thrown by getUploadFile in the SMS-incoming handler when the fetched file URL returns a non-200 status or an empty body. Rocket.Chat fetches SMS attachments (MMS) from the provider's URL, validates SSRF against the allow-list, then rejects empty or failed downloads with this Meteor.Error.","triggerScenarios":"POST livechat/sms-incoming/:service where the parsed attachment fileUrl returns 404/403/500 or a 200 with zero bytes. Also when the URL host is not in SSRF_Allowlist the fetch may resolve to a non-200 (SSRF rejection surfaces differently but can still produce non-200).","commonSituations":"SMS/MMS provider link expired or revoked; provider serves a redirect to a CDN that 404s; provider returns 200 with empty body on unsupported media; the fileUrl is behind auth the Rocket.Chat server cannot satisfy; SSRF_Allowlist misconfigured so the fetch is denied and returns non-200.","solutions":["Verify the fileUrl is reachable from the Rocket.Chat server (curl -I from the host).","Add the provider/CDN domain to the SSRF_Allowlist setting if the fetch is being denied.","Coordinate with the SMS provider to keep attachment URLs alive long enough to fetch.","Log response.status and contentSize to identify provider vs network issues; retry transient 5xx."],"exampleFix":"// before\nconst content = await fetchAttachment(providerUrl); // black-box\n\n// after\nconst resp = await fetch(providerUrl, { allowList: settings.get('SSRF_Allowlist') });\nif (resp.status !== 200 || (await resp.arrayBuffer()).byteLength === 0) {\n  logger.warn('attachment fetch failed', { status: resp.status, url: providerUrl });\n  return; // drop the attachment, keep the text\n}\nawait storeAttachment(resp);","handlingStrategy":"try-catch","validationCode":"async function preflightAttachment(url: string, allowList: string) {\n  const resp = await fetch(url, { allowList });\n  if (resp.status !== 200) return { ok: false, status: resp.status };\n  const buf = await resp.arrayBuffer();\n  return { ok: buf.byteLength > 0, size: buf.byteLength };\n}","typeGuard":"null","tryCatchPattern":"try {\n  await processSmsIncoming(payload);\n} catch (e) {\n  if (e.error === 'error-invalid-file-uploaded') { logger.warn('attachment dropped', e); return API.v1.success(); /* still accept text */ }\n  throw e;\n}","preventionTips":["Add the SMS provider/CDN hosts to SSRF_Allowlist.","Fetch attachments promptly before provider URLs expire.","Log response.status and size to distinguish provider outages from config issues."],"tags":["omnichannel","livechat","sms","file-upload","ssrf","external-fetch"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}