RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-recipient
error-invalid-recipient
Error message
error-invalid-recipient
What it means
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'.
Source
Thrown at apps/meteor/server/api/v1/rooms.ts:1054
}
void dataExport.sendFile(
{
rid,
format,
dateFrom: convertedDateFrom,
dateTo: convertedDateTo,
},
user,
);
return API.v1.success();
}
if (type === 'email') {
const { toUsers, toEmails, subject, messages } = this.bodyParams;
if ((!toUsers || toUsers.length === 0) && (!toEmails || toEmails.length === 0)) {
throw new Meteor.Error('error-invalid-recipient');
}
const result = await dataExport.sendViaEmail(
{
rid,
toUsers: (toUsers as string[]) || [],
toEmails: toEmails || [],
subject: subject || '',
messages: messages || [],
language: user.language || 'en',
},
user,
);
return API.v1.success(result);
}
return API.v1.failure();View on GitHub (pinned to f9d3ec372b)
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.
Example fix
// before
await rest.post('/api/v1/rooms.mail', { rid, type:'email', subject, messages });
// after
const recipients = collectRecipients(); // { toUsers?, toEmails? }
if (!recipients.toUsers?.length && !recipients.toEmails?.length) {
return notifyUser('Add at least one recipient.');
}
await rest.post('/api/v1/rooms.mail', { rid, type:'email', ...recipients, subject, messages }); Defensive patterns
Strategy: validation
Validate before calling
const toUsers = (recipients.usernames ?? []).filter(Boolean);
const toEmails = (recipients.emails ?? []).filter(Boolean);
if (toUsers.length === 0 && toEmails.length === 0) {
throw new Error('At least one recipient is required');
} Type guard
function hasRecipient(r: { toUsers?: unknown[]; toEmails?: unknown[] }): boolean {
return (!!r.toUsers && r.toUsers.length > 0) || (!!r.toEmails && r.toEmails.length > 0);
} Try / catch
try {
await rest.post('/api/v1/rooms.mail', { rid, type:'email', toUsers, toEmails, subject, messages });
} catch (e) {
if (isMeteorError(e, 'error-invalid-recipient')) {
notify('Add at least one recipient.');
} else throw e;
} Prevention
- Require >=1 recipient in the UI before enabling submit.
- Separate usernames (toUsers) from raw addresses (toEmails).
- Validate arrays are non-empty client-side.
When it happens
Trigger: POST /api/v1/rooms.mail with { type:'email' } and toUsers missing/empty AND toEmails missing/empty.
Common situations: Recipient picker left empty; recipients removed client-side but submit still fires; integration that only fills subject/messages.
Related errors
- error-invalid-dates
- The "${name}" parameter must be a valid date.
- error-duplicate-role-names-not-allowed
- error-room-not-found
- The required "mid" body param is missing.
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/f7ecd60410da0161.
Report an issue: GitHub.