{"record":{"id":"133ae0281942ccad","repo":"RocketChat/Rocket.Chat","slug":"error-user-not-found-133ae0","errorCode":"error-user-not-found","errorMessage":"User not found","messagePattern":"User not found","errorType":"exception","errorClass":"MeteorError","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/users/saveUser/saveUser.ts","lineNumber":108,"sourceCode":"\t\tlet sendPassword = false;\n\n\t\tif (userData.hasOwnProperty('setRandomPassword')) {\n\t\t\tif (userData.setRandomPassword) {\n\t\t\t\tuserData.password = generatePassword();\n\t\t\t\tuserData.requirePasswordChange = true;\n\t\t\t\tsendPassword = true;\n\t\t\t}\n\n\t\t\tdelete userData.setRandomPassword;\n\t\t}\n\n\t\tif (!isUpdateUserData(userData)) {\n\t\t\t// TODO audit new users\n\t\t\treturn saveNewUser(userData, sendPassword, performedBy);\n\t\t}\n\n\t\tif (!oldUserData) {\n\t\t\tthrow new MeteorError('error-user-not-found', 'User not found', {\n\t\t\t\tmethod: 'saveUser',\n\t\t\t});\n\t\t}\n\n\t\toptions?.auditStore?.setOriginalUser(oldUserData);\n\n\t\tawait validateUserEditing(userId, userData);\n\n\t\t// update user\n\t\tconst updater = Users.getUpdater();\n\n\t\tif (userData.hasOwnProperty('username') || userData.hasOwnProperty('name')) {\n\t\t\tif (\n\t\t\t\t!(await saveUserIdentity({\n\t\t\t\t\t_id: userData._id,\n\t\t\t\t\tusername: userData.username,\n\t\t\t\t\tname: userData.name,\n\t\t\t\t\tupdateUsernameInBackground: true,","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/users/saveUser/saveUser.ts#L90-L126","documentation":"saveUser throws error-user-not-found (method 'saveUser') on the update path: userData has an _id (isUpdateUserData true) but Users.findOneById(userData._id) returned null. The target of the update does not exist; only inserts without _id, or updates against an existing record, are valid.","triggerScenarios":"Calling saveUser with an _id that was deleted, a fabricated ObjectId from tests, or a race where the user is removed between the client loading the edit form and submitting it.","commonSituations":"Stale edit forms open in a browser while an admin deletes the account; tooling upserting by guessing ids instead of looking them up; cross-environment id confusion (dev id against prod data).","solutions":["Look the user up by a stable key (username/email) to resolve the current _id right before saving","Treat this error as a 404 and refresh the client's copy of the user","Never fabricate _ids for updates; omit _id to create, or query it first"],"exampleFix":"// before\nawait saveUser(actorId, { _id, name: 'New Name' }); // stale _id -> error-user-not-found\n\n// after\nconst existing = await Users.findOneByUsernameIgnoringCase(username);\nif (!existing) throw new Error('User no longer exists');\nawait saveUser(actorId, { _id: existing._id, name: 'New Name' });","handlingStrategy":"validation","validationCode":"if (userData._id) {\n  const existing = await Users.findOneById(userData._id, { projections: { _id: 1 } });\n  if (!existing) throw new Error('Target user no longer exists');\n}\nawait saveUser(actorId, userData);","typeGuard":"const isUpdateOfExistingUser = async (id: string): Promise<boolean> =>\n  !!(await Users.findOneById(id, { projections: { _id: 1 } }));","tryCatchPattern":"try {\n  await saveUser(actorId, userData);\n} catch (e) {\n  if (isMeteorErrorCode(e, 'error-user-not-found')) {\n  \trefreshUserEditor(); // target vanished; reload instead of retrying blindly\n  }\n}","preventionTips":["Resolve _id from username/email immediately before the update call","Handle 404-style refreshes in long-lived edit forms"],"tags":["users","save-user","lookup","update"],"backgroundTag":"user-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}