RocketChat/Rocket.Chat · error · Error
Invalid reaction
Error message
Invalid reaction
What it means
Thrown by the Apps Engine MessageBridge implementation when an App calls addReaction with a reaction string that fails the format check isValidReaction (must start and end with ':'). The bridge guards the input before delegating to executeSetReaction, which itself normalizes colons and validates the emoji against the built-in and custom emoji tables. It is a pure input-shape validation error, not a persistence or permissions error.
Source
Thrown at apps/meteor/app/apps/server/bridges/messages.ts:126
case 'room':
if (!username) {
throw new Error('Invalid username');
}
notifications.notifyRoom(id, 'user-activity', username, isTyping ? ['user-typing'] : []);
return;
default:
throw new Error('Unrecognized typing scope provided');
}
}
private isValidReaction(reaction: Reaction): boolean {
return reaction.startsWith(':') && reaction.endsWith(':');
}
protected async addReaction(messageId: string, userId: string, reaction: Reaction): Promise<void> {
if (!this.isValidReaction(reaction)) {
throw new Error('Invalid reaction');
}
return executeSetReaction(userId, reaction, messageId, true);
}
protected async removeReaction(messageId: string, userId: string, reaction: Reaction): Promise<void> {
if (!this.isValidReaction(reaction)) {
throw new Error('Invalid reaction');
}
return executeSetReaction(userId, reaction, messageId, false);
}
}
View on GitHub (pinned to f9d3ec372b)
Solutions
- Wrap the reaction identifier in colons before calling addReaction: pass ':smile:' rather than 'smile'.
- Centralize reaction literals in a typed constant map keyed by colon-wrapped names so callers cannot pass a bare name.
- If the reaction comes from external input, run a normalize step: `reaction = reaction.startsWith(':') ? reaction : ':' + reaction; reaction = reaction.endsWith(':') ? reaction : reaction + ':';`
- Verify the emoji actually exists (built-in emoji.list or a custom emoji alias) before calling, otherwise executeSetReaction will throw a separate 'Invalid emoji provided' Meteor error even after this guard passes.
Example fix
// before await modify.getUpdater().getReactionSetter().reactToMessage(messageId, 'thumbsup'); // after await modify.getUpdater().getReactionSetter().reactToMessage(messageId, ':thumbsup:');
Defensive patterns
Strategy: validation
Validate before calling
function normalizeReaction(reaction: string): string {
if (typeof reaction !== 'string' || reaction.length === 0) {
throw new Error('Reaction must be a non-empty string');
}
let r = reaction;
if (!r.startsWith(':')) r = ':' + r;
if (!r.endsWith(':')) r = r + ':';
return r;
}
// call before addReaction
const safe = normalizeReaction(reaction); Type guard
function isValidReaction(reaction: unknown): reaction is string {
return typeof reaction === 'string' && reaction.startsWith(':') && reaction.endsWith(':') && reaction.length >= 2;
} Prevention
- Store all emoji constants in a single map keyed by the colon-wrapped form (':thumbsup:', ':heart:').
- Run the reaction through a normalize helper at every external boundary (webhook payload, UI payload, config).
- Add a unit test asserting every constant in your emoji map passes the startsWith/endsWith colon check.
When it happens
Trigger: An App calls the messages accessor's reaction API (e.g. modify.getUpdater().getReactionSetter() or equivalent) passing a bare emoji name like 'smile' or '+1' instead of the colon-wrapped form ':smile:'. Also triggered if the reaction string is empty or only has one colon, since startsWith(':') && endsWith(':') would be false for ':' alone when length is 1 (startsWith and endsWith both true, so ':' passes — but ':smile' or 'smile:' fail). Any reaction literal lacking both bounding colons hits this branch.
Common situations: Apps authored against documentation examples that omit the colons; hardcoded emoji constants copied from picker output (which often drops colons); dynamically built reaction strings where the leading/trailing colon was stripped during templating; migration from an older Apps Engine version whose API tolerated bare names.
Related errors
- Invalid Api parameter provided, it must be a valid IApi obje
- Invalid command parameter provided, must be a string.
- Invalid Slash Command parameter provided, it must be a valid
- The environmental variable "${envVarName}" is not readable.
- auth option should be of the form "username:password"
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/d9e495f3d353dc06.
Report an issue: GitHub.