{"record":{"id":"9f44b27f1704432e","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-9f44b2","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/users/saveUserProfile.ts","lineNumber":49,"sourceCode":"\t\trealname?: string;\n\t\tnewPassword?: string;\n\t\tstatusText?: string;\n\t\tstatusType?: string;\n\t\tbio?: string;\n\t\tnickname?: string;\n\t},\n\tcustomFields: Record<string, unknown>,\n\t..._: unknown[]\n) {\n\tconst unset: UpdateFilter<IUser> = {};\n\tif (!rcSettings.get<boolean>('Accounts_AllowUserProfileChange')) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'saveUserProfile',\n\t\t});\n\t}\n\n\tif (!this.userId) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'saveUserProfile',\n\t\t});\n\t}\n\n\tawait validateUserEditing(this.userId, {\n\t\t_id: this.userId,\n\t\temail: settings.email,\n\t\tusername: settings.username,\n\t\tname: settings.realname,\n\t\tpassword: settings.newPassword,\n\t\tstatusText: settings.statusText,\n\t});\n\n\tconst user = await Users.findOneById(this.userId);\n\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'saveUserProfile',","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/saveUserProfile.ts#L31-L67","documentation":"Thrown by 'saveUserProfile' when this.userId is null inside the method invocation: the DDP call carried no valid login token (or it expired). It is the standard logged-in guard, evaluated right after the Accounts_AllowUserProfileChange gate and before validateUserEditing permission checks.","triggerScenarios":"Calling 'saveUserProfile' after the user logged out or the resume token expired; components surviving a session reset that still submit the profile form; DDP scripts that never logged in.","commonSituations":"Profile form submitted after background logout; multi-tab scenarios where one tab logs out and another submits.","solutions":["Guard submissions with Meteor.userId() and re-authenticate/redirect on null.","Disable the form reactively when the user session ends.","For server-to-server use, call PUT /api/v1/users.update with admin auth instead of the user-scoped DDP method."],"exampleFix":"// before\nsubmit = (data) => Meteor.callAsync('saveUserProfile', data, customFields);\n\n// after\nsubmit = (data) => {\n  if (!Meteor.userId()) { FlowRouter.go('/login'); return; }\n  Meteor.callAsync('saveUserProfile', data, customFields);\n}","handlingStrategy":"validation","validationCode":"if (!Meteor.userId()) {\n  FlowRouter.go('/login');\n} else {\n  await Meteor.callAsync('saveUserProfile', settings, customFields);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Meteor.callAsync('saveUserProfile', settings, customFields);\n} catch (e) {\n  if ((e as Meteor.Error).error === 'error-invalid-user') {\n    disableForm();\n    handleSessionExpired();\n  }\n}","preventionTips":["Disable the profile form reactively when the session ends","Re-login before retrying after session expiry","Treat error-invalid-user from DDP methods as a session-expiry signal everywhere"],"tags":["authentication","session-expired","profile","meteor-method"],"backgroundTag":"user-not-authenticated","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}