RocketChat/Rocket.Chat · error · Error
invalid-token
Error message
invalid-token
What it means
Thrown by GET /api/v1/livechat/room when the visitor lookup fails. Because the handler first runs check(this.queryParams, { token: String, rid: Match.Maybe(String), ... }) (extensible via the onCheckRoomParams patch point), a missing token raises a Match validation error instead — so 'invalid-token' here means the token value matched no LivechatVisitors document, or an injected onCheckRoomParams hook made token optional.
Solutions
- Register the visitor first (POST /api/v1/livechat/visitor) or let the widget's registration flow complete, then call livechat/room with the issued token.
- Confirm the token survives storage round-trips (no whitespace/newlines) and matches the environment.
- If you extended onCheckRoomParams, keep token required in the Match pattern so missing tokens fail validation with a clearer message.
Example fix
// before (room requested with a fabricated token)
await fetch(`/api/v1/livechat/room?token=my-invented-token`);
// after (register visitor, then create/obtain the room)
const v = await (await fetch('/api/v1/livechat/visitor', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ visitor: { token: 'tkn1', name: 'Lead' } }) })).json();
await fetch(`/api/v1/livechat/room?token=${v.visitor.token}`); Defensive patterns
Strategy: validation
Validate before calling
// livechat/room does NOT register visitors — register first
await ensureRegisteredVisitor({ token });
const res = await fetch(`/api/v1/livechat/room?token=${encodeURIComponent(token)}`); Try / catch
if (isLivechatErrorResponse(body) && body.error === 'invalid-token') {
await ensureRegisteredVisitor({ token }); // register then retry room creation once
} Prevention
- Never assume livechat/room auto-creates visitors; only livechat/messages does fallback registration.
- Keep the registration and room-open calls sequenced in an onboarding flow.
When it happens
Trigger: GET /api/v1/livechat/room?token=<unknown> (optionally &rid=&agentId=). Known trigger sub-case: relying on this endpoint to auto-create a room but passing a token that was never registered.
Common situations: Integration calls livechat/room before registering the visitor — the endpoint does NOT register visitors (unlike livechat/messages); widget token lost from storage; Apps/custom code extending onCheckRoomParams loosening the token requirement and hitting the null path.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/6933544db48af33d.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/api/v1/omnichannel/room.ts:77
intervalTimeInMS: 60000,
},
},
{
async get() {
// I'll temporary use check for validation, as validateParams doesnt support what's being done here
const extraCheckParams = onCheckRoomParams({
token: String,
rid: Match.Maybe(String),
agentId: Match.Maybe(String),
});
check(this.queryParams, extraCheckParams);
const { token, rid, agentId, ...extraParams } = this.queryParams;
const guest = token && (await findGuest(token));
if (!guest) {
throw new Error('invalid-token');
}
if (!rid) {
const room = await LivechatRooms.findOneOpenByVisitorToken(token, {});
if (room) {
return API.v1.success({ room, newRoom: false });
}
let agent: SelectedAgent | undefined;
const agentObj = agentId && (await findAgent(agentId));
if (agentObj) {
if (isAgentWithInfo(agentObj)) {
const { username = undefined } = agentObj;
agent = { agentId, username };
} else {
agent = { agentId };
}
}View on GitHub (pinned to b2c16d5842)