{"record":{"id":"1d44e3de93cfb9de","repo":"RocketChat/Rocket.Chat","slug":"invalid-token-1d44e3","errorCode":null,"errorMessage":"invalid-token","messagePattern":"invalid-token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/message.ts","lineNumber":33,"sourceCode":"import { findGuest, findRoom, normalizeHttpHeaderData } from './lib/livechat';\nimport { callbacks } from '../../../lib/callbacks';\nimport { loadMessageHistory } from '../../../lib/messages/loadMessageHistory';\nimport { updateMessage, deleteMessage, sendMessage } from '../../../lib/omnichannel/messages';\nimport { normalizeMessageFileUpload } from '../../../lib/utils/functions/normalizeMessageFileUpload';\nimport { settings } from '../../../settings';\nimport { getPaginationItems } from '../../lib/getPaginationItems';\nimport { isWidget } from '../../lib/isWidget';\n\nAPI.v1.addRoute(\n\t'livechat/message',\n\t{ validateParams: isPOSTLivechatMessageParams },\n\t{\n\t\tasync post() {\n\t\t\tconst { token, rid, agent, msg } = this.bodyParams;\n\n\t\t\tconst guest = await findGuest(token);\n\t\t\tif (!guest) {\n\t\t\t\tthrow new Error('invalid-token');\n\t\t\t}\n\n\t\t\tconst room = await findRoom(token, rid);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tif (!room.open) {\n\t\t\t\tthrow new Error('room-closed');\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tsettings.get('Livechat_enable_message_character_limit') &&\n\t\t\t\tmsg.length > parseInt(settings.get('Livechat_message_character_limit'))\n\t\t\t) {\n\t\t\t\tthrow new Error('message-length-exceeds-character-limit');\n\t\t\t}\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/message.ts#L15-L51","documentation":"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' }.","triggerScenarios":"POST /livechat/message with an unknown, stale, typo'd, or empty `token` in the body.","commonSituations":"Widget token expired/purged; visitor re-registered with a new token; sending `_id` instead of `token`.","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."],"exampleFix":"// before\nPOST /livechat/message { token: stale, rid, msg }\n\n// after\nconst guest = await findGuest(token);\nif (!guest) { /* re-register visitor, then retry */ }\nPOST /livechat/message { token: guest.token, rid, msg }","handlingStrategy":"validation","validationCode":"const guest = await findGuest(token);\nif (!guest) {\n  // re-register visitor, then retry the send\n  throw new Error('visitor token invalid');\n}\n// safe to POST /livechat/message","typeGuard":"const isGuest = (g: unknown): g is ILivechatVisitor =>\n  !!g && typeof g === 'object' && typeof (g as any).token === 'string';","tryCatchPattern":"try { await sendMessage({ token, rid, msg }); }\ncatch (e) { if (e instanceof Error && e.message === 'invalid-token') { /* refresh token, retry once */ } else throw e; }","preventionTips":["Resolve the visitor before sending; persist the token with the session.","Never send `_id` as `token`.","Re-register after visitor purge."],"tags":["livechat","omnichannel","visitor-token","messaging","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}