{"record":{"id":"f7ecd60410da0161","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-recipient","errorCode":"error-invalid-recipient","errorMessage":"error-invalid-recipient","messagePattern":"error-invalid-recipient","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/rooms.ts","lineNumber":1054,"sourceCode":"\t\t\t}\n\n\t\t\tvoid dataExport.sendFile(\n\t\t\t\t{\n\t\t\t\t\trid,\n\t\t\t\t\tformat,\n\t\t\t\t\tdateFrom: convertedDateFrom,\n\t\t\t\t\tdateTo: convertedDateTo,\n\t\t\t\t},\n\t\t\t\tuser,\n\t\t\t);\n\t\t\treturn API.v1.success();\n\t\t}\n\n\t\tif (type === 'email') {\n\t\t\tconst { toUsers, toEmails, subject, messages } = this.bodyParams;\n\n\t\t\tif ((!toUsers || toUsers.length === 0) && (!toEmails || toEmails.length === 0)) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-recipient');\n\t\t\t}\n\n\t\t\tconst result = await dataExport.sendViaEmail(\n\t\t\t\t{\n\t\t\t\t\trid,\n\t\t\t\t\ttoUsers: (toUsers as string[]) || [],\n\t\t\t\t\ttoEmails: toEmails || [],\n\t\t\t\t\tsubject: subject || '',\n\t\t\t\t\tmessages: messages || [],\n\t\t\t\t\tlanguage: user.language || 'en',\n\t\t\t\t},\n\t\t\t\tuser,\n\t\t\t);\n\n\t\t\treturn API.v1.success(result);\n\t\t}\n\n\t\treturn API.v1.failure();","sourceCodeStart":1036,"sourceCodeEnd":1072,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/rooms.ts#L1036-L1072","documentation":"Thrown by POST rooms.mail (type 'email') when neither toUsers nor toEmails is supplied (or both are empty arrays). The email path needs at least one recipient; with none it cannot deliver. Note: carries no human message — only the code 'error-invalid-recipient'.","triggerScenarios":"POST /api/v1/rooms.mail with { type:'email' } and toUsers missing/empty AND toEmails missing/empty.","commonSituations":"Recipient picker left empty; recipients removed client-side but submit still fires; integration that only fills subject/messages.","solutions":["Require at least one recipient in the UI before enabling submit.","If only usernames are available, put them in toUsers; if only addresses, in toEmails.","Validate non-empty arrays on the client and show a helpful message."],"exampleFix":"// before\nawait rest.post('/api/v1/rooms.mail', { rid, type:'email', subject, messages });\n\n// after\nconst recipients = collectRecipients(); // { toUsers?, toEmails? }\nif (!recipients.toUsers?.length && !recipients.toEmails?.length) {\n  return notifyUser('Add at least one recipient.');\n}\nawait rest.post('/api/v1/rooms.mail', { rid, type:'email', ...recipients, subject, messages });","handlingStrategy":"validation","validationCode":"const toUsers = (recipients.usernames ?? []).filter(Boolean);\nconst toEmails = (recipients.emails ?? []).filter(Boolean);\nif (toUsers.length === 0 && toEmails.length === 0) {\n  throw new Error('At least one recipient is required');\n}","typeGuard":"function hasRecipient(r: { toUsers?: unknown[]; toEmails?: unknown[] }): boolean {\n  return (!!r.toUsers && r.toUsers.length > 0) || (!!r.toEmails && r.toEmails.length > 0);\n}","tryCatchPattern":"try {\n  await rest.post('/api/v1/rooms.mail', { rid, type:'email', toUsers, toEmails, subject, messages });\n} catch (e) {\n  if (isMeteorError(e, 'error-invalid-recipient')) {\n    notify('Add at least one recipient.');\n  } else throw e;\n}","preventionTips":["Require >=1 recipient in the UI before enabling submit.","Separate usernames (toUsers) from raw addresses (toEmails).","Validate arrays are non-empty client-side."],"tags":["validation","mail","recipients","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}