RocketChat/Rocket.Chat · error · Meteor.Error

invalid-command-usage

invalid-command-usage

Error message

Executing a command requires at least a message with a room id.

What it means

slashCommands.run() refuses to execute a registered slash command when the message object has no rid, because every command callback needs a room context to act in. The (deprecated, use POST /v1/commands.run) Meteor method 'slashCommand' forwards the client's msg here, so an empty or partial msg surfaces as invalid-command-usage. Unknown or unregistered commands are silently ignored earlier by the callback check, so this error implies the command itself was found.

Source

Thrown at apps/meteor/server/lib/utils/slashCommand.ts:76

		command,
		message,
		params,
		triggerId,
		userId,
	}: {
		command: string;
		params: string;
		message: RequiredField<Partial<IMessage>, 'rid' | '_id'>;
		userId: string;
		triggerId?: string | undefined;
	}): Promise<unknown> {
		const cmd = this.commands[command];
		if (typeof cmd?.callback !== 'function') {
			return;
		}

		if (!message?.rid) {
			throw new MeteorError('invalid-command-usage', 'Executing a command requires at least a message with a room id.');
		}

		return cmd.callback({ command, params, message, triggerId, userId });
	},
	async getPreviews(
		command: string,
		params: string,
		message: RequiredField<Partial<IMessage>, 'rid'>,
		userId: string,
	): Promise<SlashCommandPreviews | undefined> {
		const cmd = this.commands[command];
		if (typeof cmd?.previewer !== 'function') {
			return;
		}

		if (!message?.rid) {
			throw new MeteorError('invalid-command-usage', 'Executing a command requires at least a message with a room id.');
		}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Build the message with at least { _id, rid } before calling slashCommands.run or the DDP method.
  2. Prefer REST POST /api/v1/commands.run with command/roomId/params, which constructs the message server-side.
  3. In server code, pass the target room's id explicitly on every command invocation.

Example fix

// before: no rid -> invalid-command-usage
await slashCommands.run({
  command: 'gimme',
  params: 'a cat picture',
  message: { _id: Random.id() } as any,
  userId,
});

// after
await slashCommands.run({
  command: 'gimme',
  params: 'a cat picture',
  message: { _id: Random.id(), rid: roomId },
  userId,
});
Defensive patterns

Strategy: type-guard

Validate before calling

if (!hasRoomId(message)) {
  throw new Error('refusing to run slash command without a room');
}
await slashCommands.run({ command, params, message, userId });

Type guard

const hasRoomId = (m: unknown): m is { rid: string } =>
  typeof m === 'object' &&
  m !== null &&
  typeof (m as { rid?: unknown }).rid === 'string' &&
  (m as { rid: string }).rid.length > 0;

Try / catch

try {
  await Meteor.callAsync('slashCommand', { cmd, params, msg });
} catch (err: any) {
  if (err?.error === 'invalid-command-usage') {
    // msg.rid was missing: re-attach the room id and retry once
    return Meteor.callAsync('slashCommand', { cmd, params, msg: { ...msg, rid: currentRoomId } });
  }
  throw err;
}

Prevention

When it happens

Trigger: Meteor.call('slashCommand', { cmd, params, msg }) with msg.rid undefined; server code calling slashCommands.run({ command, params, message: {} as any, userId }); command-palette UI forwarding a draft message that was never attached to a room.

Common situations: Bots/integrations invoking slash commands without a room; hand-built message objects that only set _id or text; refactors that dropped rid from composer state before send.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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