{"record":{"id":"8096da246c9dd1e8","repo":"RocketChat/Rocket.Chat","slug":"message-not-found-8096da","errorCode":null,"errorMessage":"message-not-found","messagePattern":"message-not-found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/lib/getPermaLink.ts","lineNumber":24,"sourceCode":"\ttry {\n\t\tconst { sdk } = await import('../../app/utils/client/lib/SDKClient');\n\t\tconst { message } = await sdk.rest.get('/v1/chat.getMessage', { msgId });\n\t\treturn message;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nexport const getPermaLink = async (msgId: string): Promise<string> => {\n\tif (!msgId) {\n\t\tthrow new Error('invalid-parameter');\n\t}\n\n\tconst { Messages, Rooms, Subscriptions } = await import('../stores');\n\n\tconst msg = Messages.state.get(msgId) || (await getMessage(msgId));\n\tif (!msg) {\n\t\tthrow new Error('message-not-found');\n\t}\n\tconst roomData = Rooms.state.get(msg.rid);\n\n\tif (!roomData) {\n\t\tthrow new Error('room-not-found');\n\t}\n\n\tconst subData = Subscriptions.state.find((record) => record.rid === roomData._id && record.u._id === getUserId());\n\n\tconst { roomCoordinator } = await import('./rooms/roomCoordinator');\n\n\tconst roomURL = roomCoordinator.getURL(roomData.t, { ...(subData || roomData), tab: '' });\n\treturn `${roomURL}?msg=${msgId}`;\n};\n","sourceCodeStart":6,"sourceCodeEnd":39,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/lib/getPermaLink.ts#L6-L39","documentation":"Thrown by getPermaLink after it fails to find the message in both the local Messages store AND via a server REST API call to /v1/chat.getMessage. The function first checks the client cache (Messages.state.get), and if missing, calls getMessage which hits the API. If both return null/falsy, the message truly does not exist or the user lacks permission to read it.","triggerScenarios":"The message ID refers to a message that was deleted. The message exists but the user does not have read permission in the room. The message ID is valid but belongs to a room the user cannot access. Network error during the REST call causes getMessage to return null (it swallows errors in its catch block). Server is temporarily unreachable.","commonSituations":"Copying a link to a message that was deleted between page load and link generation. Message belongs to a private channel the user was removed from. Stale message ID from a bookmark or external link. Transient network failure during the API fallback.","solutions":["Catch the 'message-not-found' error in the caller and show a user-facing message like 'This message is no longer available'.","Verify the message exists in the local cache before calling getPermaLink for messages the user is currently viewing.","Check the user has access to the room containing the message before generating a permalink.","Note that getMessage's internal catch block silently returns null on network errors — retry getPermaLink on transient failures."],"exampleFix":"// before\ntry {\n  const link = await getPermaLink(msgId);\n} catch (e) { /* unhandled */ }\n// after\ntry {\n  const link = await getPermaLink(msgId);\n} catch (e) {\n  if (e instanceof Error && e.message === 'message-not-found') {\n    dispatchToastMessage({ type: 'error', message: t('Message_not_available') });\n    return;\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const msg = Messages.state.get(msgId);\nif (!msg) {\n  // optionally try API, or show 'not available'\n  return;\n}\nconst link = await getPermaLink(msgId);","typeGuard":"const messageExistsInCache = (msgId: string): boolean =>\n  Boolean(Messages.state.get(msgId));","tryCatchPattern":"try {\n  const link = await getPermaLink(msgId);\n} catch (e) {\n  if (e instanceof Error && e.message === 'message-not-found') {\n    dispatchToastMessage({ type: 'error', message: t('Message_not_available') });\n    return;\n  }\n  throw e;\n}","preventionTips":["Check the Messages store before calling getPermaLink for locally available messages.","Catch 'message-not-found' explicitly in permalink-generating code paths.","Be aware that getMessage's internal catch block swallows network errors, returning null — retry on transient failures."],"tags":["permalink","message-not-found","api-call","permissions","cache"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}