{"record":{"id":"0d7726f345325370","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-0d7726","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"exception","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/im.ts","lineNumber":59,"sourceCode":"import type { ExtractRoutesFromAPI } from '../ApiClass';\nimport { API } from '../api';\nimport type { TypedAction } from '../definition';\nimport { addUserToFileObj } from '../lib/addUserToFileObj';\nimport { composeRoomWithLastMessage } from '../lib/composeRoomWithLastMessage';\nimport { getPaginationItems } from '../lib/getPaginationItems';\n\nconst findDirectMessageRoom = async (\n\tkeys: { roomId?: string; username?: string },\n\tuid: string,\n): Promise<{ room: IRoom; subscription: ISubscription | null }> => {\n\tconst nameOrId = 'roomId' in keys ? keys.roomId : keys.username;\n\tif (typeof nameOrId !== 'string') {\n\t\tthrow new Meteor.Error('error-room-param-not-provided', 'Query param \"roomId\" or \"username\" is required');\n\t}\n\n\tconst user = await Users.findOneById(uid);\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'findDirectMessageRoom',\n\t\t});\n\t}\n\n\tconst room = await getRoomByNameOrIdWithOptionToJoin({\n\t\tuser,\n\t\tnameOrId,\n\t\ttype: 'd',\n\t});\n\n\tif (!room || room?.t !== 'd') {\n\t\tthrow new Meteor.Error('error-room-not-found', 'The required \"roomId\" param provided does not match any direct message');\n\t}\n\n\tconst subscription = await Subscriptions.findOne({ 'rid': room._id, 'u._id': uid });\n\n\treturn {\n\t\troom,","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/api/v1/im.ts#L41-L77","documentation":"Thrown by findDirectMessageRoom (apps/meteor/server/api/v1/im.ts:56) when Users.findOneById(uid) returns null: the request was resolved to a userId, but no user document with that _id exists in the `users` collection. The credentials pair (token + userId) points at an account that has been deleted or never existed.","triggerScenarios":"The authenticated user was deleted (admin action, GDPR/retention purge) while their REST token or personal access token was still being sent; a hand-crafted X-User-Id paired with a token that no longer maps to a live user; database restored from a backup missing that user record.","commonSituations":"Long-lived personal access tokens or OAuth tokens outliving their accounts; test suites with stale fixture user IDs after a DB reset; user-deletion jobs that forget to revoke tokens, so clients get this error instead of a clean 401.","solutions":["Re-authenticate: log in as an existing user (or mint a new personal access token) and retry with the new X-User-Id / X-Auth-Token pair","Confirm the user exists: GET /api/v1/users.info?userId=... as an admin","If a deletion job removed the user, also revoke/invalidate that user's tokens so future calls fail with a proper auth error","In tests, recreate user fixtures and re-derive tokens after every database reset"],"exampleFix":"// before — token belongs to a deleted user\nconst headers = { 'X-User-Id': deletedUserId, 'X-Auth-Token': staleToken };\nawait get('/api/v1/im.messages', { username: 'alice' }, { headers }); // error-invalid-user\n\n// after — validate credentials once, then re-login on failure\nconst me = await get('/api/v1/me', {}, { headers });\nif (!me.success) {\n  const { data } = await post('/api/v1/login', { user, password });\n  headers['X-User-Id'] = data.userId;\n  headers['X-Auth-Token'] = data.authToken;\n}\nawait get('/api/v1/im.messages', { username: 'alice' }, { headers });","handlingStrategy":"validation","validationCode":"const me = await fetch('/api/v1/me', { headers: { 'X-Auth-Token': token, 'X-User-Id': uid } });\nif (me.status === 401 || (me.ok && (await me.json()).success === false)) {\n  // token/user pair no longer resolves to a live account — re-login before any im.* call\n  throw new Error('credentials stale: re-authenticate');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await get('/api/v1/im.messages', { roomId });\n} catch (e) {\n  if (e?.body?.errorType === 'error-invalid-user' && 'method' in (e.body?.details ?? {})) {\n    // userId behind the token no longer exists: drop cached credentials, re-login or abort\n    await invalidateCachedCredentials();\n  }\n  throw e;\n}","preventionTips":["Validate credentials with GET /api/v1/me at client startup and after any 401-ish failure","Invalidate tokens server-side whenever users are deleted","Never cache user tokens across database resets/restores in test environments"],"tags":["rest-api","im","authentication","user-deleted","invalid-user"],"backgroundTag":"api-user-not-found","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}