{"record":{"id":"b6d82b9a3a2650d0","repo":"RocketChat/Rocket.Chat","slug":"error-user-not-found","errorCode":null,"errorMessage":"error-user-not-found","messagePattern":"error-user-not-found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/lib/syncUserRoles.ts","lineNumber":63,"sourceCode":"\t\tvoid api.broadcast('user.roleUpdate', {\n\t\t\ttype,\n\t\t\t_id: roleId,\n\t\t\tu: {\n\t\t\t\t_id,\n\t\t\t\tusername,\n\t\t\t},\n\t\t});\n\t}\n}\n\nexport async function syncUserRoles(\n\tuid: IUser['_id'],\n\tnewRoleList: Array<IRole['_id']>,\n\t{ allowedRoles, skipRemovingRoles, scope }: setUserRolesOptions,\n): Promise<void> {\n\tconst user = await Users.findOneById<Pick<IUser, '_id' | 'username' | 'roles'>>(uid, { projection: { username: 1, roles: 1 } });\n\tif (!user) {\n\t\tthrow new Error('error-user-not-found');\n\t}\n\n\tconst existingRoles = user.roles;\n\tconst rolesToAdd = filterRoleList(newRoleList, existingRoles, allowedRoles);\n\tconst rolesToRemove = filterRoleList(existingRoles, newRoleList, allowedRoles);\n\n\tif (!rolesToAdd.length && !rolesToRemove.length) {\n\t\treturn;\n\t}\n\n\tconst wasGuest = existingRoles.length === 1 && existingRoles[0] === 'guest';\n\tif (wasGuest && (await License.shouldPreventAction('activeUsers'))) {\n\t\tthrow new Error('error-license-user-limit-reached');\n\t}\n\n\tif (rolesToAdd.length && (await addUserRolesAsync(uid, rolesToAdd, scope))) {\n\t\tbroadcastRoleChange('added', rolesToAdd, user);\n\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/lib/syncUserRoles.ts#L45-L81","documentation":"Thrown by syncUserRoles in syncUserRoles.ts:63 when the target user (uid) cannot be found by findOneById. The function rewrites a user's role set, so a missing user is a hard precondition failure. NOTE: plain `new Error('error-user-not-found')` — code is in the message, not structured.","triggerScenarios":"Calling syncUserRoles with a uid that was deleted, never existed, or whose projection returned null. Often reached indirectly via role-assignment REST endpoints or user-edit flows.","commonSituations":"Client holds a stale uid; user was deleted between page load and role save; import job referencing archived user ids.","solutions":["Verify the user exists (Users.findOneById(uid)) before invoking syncUserRoles.","Match by message 'error-user-not-found' in the catch and refresh the user list.","Treat as no-op for archived/deleted users."],"exampleFix":"// before\nawait syncUserRoles(uid, newRoles, opts);\n\n// after\nif (!(await Users.findOneById(uid, { projection: { _id: 1 } }))) {\n  throw new Error('user missing; refresh');\n}\nawait syncUserRoles(uid, newRoles, opts);","handlingStrategy":"validation","validationCode":"if (!(await Users.findOneById(uid, { projection: { _id: 1 } }))) throw new Error('user missing');","typeGuard":"const userExists = async (uid: string) => Boolean(await Users.findOneById(uid, { projection: { _id: 1 } }));","tryCatchPattern":"try { await syncUserRoles(uid, newRoles, opts); }\ncatch (e) {\n  if (e instanceof Error && e.message === 'error-user-not-found') { /* refresh user */ return; }\n  throw e;\n}","preventionTips":["Refetch the user before role edits.","Avoid caching user ids across long sessions."],"tags":["roles","users","not-found","plain-error"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}