RocketChat/Rocket.Chat · error · Error
invalid-token
Error message
invalid-token
What it means
Thrown by POST /livechat/message (message.ts:31-34) when findGuest(token) returns null — the visitor token in the request body does not resolve to a visitor. This is the first guard in the message-send flow (before room lookup). Returns HTTP 400 { success:false, error:'invalid-token' }.
Source
Thrown at apps/meteor/server/api/v1/omnichannel/message.ts:33
import { findGuest, findRoom, normalizeHttpHeaderData } from './lib/livechat';
import { callbacks } from '../../../lib/callbacks';
import { loadMessageHistory } from '../../../lib/messages/loadMessageHistory';
import { updateMessage, deleteMessage, sendMessage } from '../../../lib/omnichannel/messages';
import { normalizeMessageFileUpload } from '../../../lib/utils/functions/normalizeMessageFileUpload';
import { settings } from '../../../settings';
import { getPaginationItems } from '../../lib/getPaginationItems';
import { isWidget } from '../../lib/isWidget';
API.v1.addRoute(
'livechat/message',
{ validateParams: isPOSTLivechatMessageParams },
{
async post() {
const { token, rid, agent, msg } = this.bodyParams;
const guest = await findGuest(token);
if (!guest) {
throw new Error('invalid-token');
}
const room = await findRoom(token, rid);
if (!room) {
throw new Error('invalid-room');
}
if (!room.open) {
throw new Error('room-closed');
}
if (
settings.get('Livechat_enable_message_character_limit') &&
msg.length > parseInt(settings.get('Livechat_message_character_limit'))
) {
throw new Error('message-length-exceeds-character-limit');
}
View on GitHub (pinned to f9d3ec372b)
Solutions
- Resolve/refresh the visitor token via /livechat/visitor before sending messages.
- Send the visitor `token`, not the `_id`.
- If the visitor is gone, re-register to obtain a fresh token and room.
Example fix
// before
POST /livechat/message { token: stale, rid, msg }
// after
const guest = await findGuest(token);
if (!guest) { /* re-register visitor, then retry */ }
POST /livechat/message { token: guest.token, rid, msg } Defensive patterns
Strategy: validation
Validate before calling
const guest = await findGuest(token);
if (!guest) {
// re-register visitor, then retry the send
throw new Error('visitor token invalid');
}
// safe to POST /livechat/message Type guard
const isGuest = (g: unknown): g is ILivechatVisitor => !!g && typeof g === 'object' && typeof (g as any).token === 'string';
Try / catch
try { await sendMessage({ token, rid, msg }); }
catch (e) { if (e instanceof Error && e.message === 'invalid-token') { /* refresh token, retry once */ } else throw e; } Prevention
- Resolve the visitor before sending; persist the token with the session.
- Never send `_id` as `token`.
- Re-register after visitor purge.
When it happens
Trigger: POST /livechat/message with an unknown, stale, typo'd, or empty `token` in the body.
Common situations: Widget token expired/purged; visitor re-registered with a new token; sending `_id` instead of `token`.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/1d44e3de93cfb9de.
Report an issue: GitHub.