{"record":{"id":"1d44e3de93cfb9de","repo":"RocketChat/Rocket.Chat","slug":"invalid-token-1d44e3","errorCode":null,"errorMessage":"invalid-token","messagePattern":"invalid-token","errorType":"exception","errorClass":"Error","httpStatus":400,"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/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/omnichannel/message.ts#L15-L51","documentation":"POST /api/v1/livechat/message (visitor sends a message) first resolves findGuest(token) → LivechatVisitors.getVisitorByToken(token). When no visitor carries that token it throws 'invalid-token' before any room or message work happens.","triggerScenarios":"Sending a livechat message with a stale/typo'd token, a token from another server, or an empty token; visitor re-registered (new token) while the sender still uses the old one.","commonSituations":"Widget localStorage cleared/reset causing token mismatch; environment migration without clearing visitor state; integrations replaying old tokens.","solutions":["Use the token issued when the visitor registered (POST /api/v1/livechat/visitor or the widget's setup flow) in this environment.","On 'invalid-token', re-register the visitor to obtain a fresh token, recreate/open the room, then resend.","Keep token and rid as an atomic pair in client state so they can never drift apart."],"exampleFix":"// before\nawait post('/api/v1/livechat/message', { token: staleToken, rid, msg: 'hi' }); // invalid-token\n\n// after\nasync function sendVisitorMessage(rid, msg) {\n  let { token } = getState();\n  try {\n    return await post('/api/v1/livechat/message', { token, rid, msg });\n  } catch (e) {\n    if (e.message !== 'invalid-token') throw e;\n    const { visitor } = await post('/api/v1/livechat/visitor', { visitor: { name: 'guest' } });\n    token = visitor.token; // persist token+rid pair together\n    return post('/api/v1/livechat/message', { token, rid: await openRoom(token), msg });\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Cheap pre-check via the token-based visitor info endpoint\nconst info = await get(`/api/v1/livechat/visitor.info/${token}`);\nif (!info?.visitor) throw new Error('re-register visitor before sending');\nawait post('/api/v1/livechat/message', { token, rid, msg });","typeGuard":null,"tryCatchPattern":"try {\n  await post('/api/v1/livechat/message', { token, rid, msg });\n} catch (e) {\n  if (e.message !== 'invalid-token') throw e;\n  const { visitor } = await post('/api/v1/livechat/visitor', { visitor: { name: 'guest' } });\n  token = visitor.token;\n  const { room } = await post('/api/v1/livechat/room', { token }); // rid must match the new token\n  await post('/api/v1/livechat/message', { token, rid: room._id, msg });\n}","preventionTips":["Persist token and rid together; never let one update without the other.","Re-register on invalid-token rather than dropping the message.","Scope tokens per environment in integration config."],"tags":["omnichannel","livechat","message","visitor-token","rest-api"],"backgroundTag":"invalid-auth-token","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}