RocketChat/Rocket.Chat · error · Meteor.Error
invalid-token
invalid-token
Error message
invalid-token
What it means
The sendMessageLivechat Meteor method (deprecated since 9.0.0 in favor of /v1/livechat/message) authenticates the sender purely by visitor token: LivechatVisitors.getVisitorByToken(token) found no matching document, so the send is rejected with invalid-token. The token must belong to an existing livechat visitor on this workspace.
Source
Thrown at apps/meteor/server/meteor-methods/omnichannel/sendMessageLivechat.ts:56
check(
agent,
Match.Maybe({
agentId: String,
username: String,
}),
);
const guest = await LivechatVisitors.getVisitorByToken(token, {
projection: {
name: 1,
username: 1,
department: 1,
token: 1,
},
});
if (!guest) {
throw new Meteor.Error('invalid-token');
}
if (settings.get('Livechat_enable_message_character_limit') && msg.length > parseInt(settings.get('Livechat_message_character_limit'))) {
throw new Meteor.Error('message-length-exceeds-character-limit');
}
return sendMessage({
guest,
message: {
_id,
rid,
msg,
token,
file,
files,
attachments,
},
agent,View on GitHub (pinned to b2c16d5842)
Solutions
- Register (or restore) the livechat visitor before sending and use the token returned by that registration for all sends
- Clear the stale guest token in the widget (localStorage) so a new visitor and token are generated
- Confirm the token comes from the same workspace/environment — tokens do not transfer across servers
Example fix
// before
Meteor.call('sendMessageLivechat', { token: staleToken, _id, rid, msg });
// after
const { visitor } = await registerLivechatVisitor(); // returns a valid token
Meteor.call('sendMessageLivechat', { token: visitor.token, _id, rid, msg }); Defensive patterns
Strategy: retry
Validate before calling
const info = await fetch(`/api/v1/livechat/visitor.info?token=${encodeURIComponent(token)}`);
if (!info.ok) {
const reg = await registerLivechatVisitor();
token = reg.token; // refresh the dead token before sending
} Type guard
const isInvalidToken = (e: unknown): e is Meteor.Error =>
typeof e === 'object' && e !== null && (e as { error?: string }).error === 'invalid-token'; Try / catch
try {
await send(token);
} catch (e) {
if (isInvalidToken(e)) {
token = (await registerLivechatVisitor()).token; // acquire a fresh, valid visitor identity
return send(token); // one retry with the new token
}
throw e;
} Prevention
- Create or restore the visitor and persist its token before any livechat send
- Treat invalid-token as session loss: regenerate the visitor token and continue instead of hard-failing
- Scope stored tokens per environment — tokens never transfer between workspaces
When it happens
Trigger: Calling sendMessageLivechat with a message whose token was never registered, belongs to another workspace/environment, or whose visitor was deleted; a stale token persisted in the widget's localStorage after a data reset or server migration.
Common situations: Livechat widget reusing an old localStorage token after the server was reinstalled or visitors purged; dev vs prod token mixups; hand-rolled integrations that invent tokens instead of registering a visitor first.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/b3249f0b0286e81f.
Report an issue: GitHub.