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

  1. Require at least one recipient in the UI before enabling submit.
  2. If only usernames are available, put them in toUsers; if only addresses, in toEmails.
  3. 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

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


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/f7ecd60410da0161. Report an issue: GitHub.