{"record":{"id":"1afb91349c944107","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-1afb91","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts","lineNumber":50,"sourceCode":"\t\t});\n\t}\n\n\tconst isFederated = isRoomFederated(room);\n\n\tif (!(await hasPermissionAsync(fromUserId, 'set-owner', rid)) && !isFederated) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tif (isFederated && !isFederationEnabled()) {\n\t\tthrow new FederationMatrixInvalidConfigurationError('unable to change room owners');\n\t}\n\n\tconst user = await Users.findOneById(userId);\n\n\tif (!user?.username) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);\n\n\tif (!subscription) {\n\t\tthrow new Meteor.Error('error-user-not-in-room', 'User is not in this room', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tif (subscription.roles && Array.isArray(subscription.roles) === true && subscription.roles.includes('owner') === true) {\n\t\tthrow new Meteor.Error('error-user-already-owner', 'User is already an owner', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts#L32-L68","documentation":"Thrown by addRoomOwner() in apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts:50 when Users.findOneById(userId) returns null or the found user has no username. Rocket.Chat identifies role targets by username for system messages and subscription lookups, so a user document without a username cannot receive the 'owner' role through this path.","triggerScenarios":"Passing a userId that does not exist (deleted user, typo'd ID, ID from another workspace); targeting a user whose username field is unset — typically incompletely provisioned accounts, users mid-deletion, or app/bot users created without a username.","commonSituations":"Inviting an owner by an ID cached from before the user was removed; user import pipelines that leave username null; LDAP/CAS provisioning that created the document but failed before setting username; passing a subscription _id instead of a user _id.","solutions":["Confirm the user exists and has a username: await Users.findOneById(userId, { projection: { username: 1 } }).","Fix the account data: set the username via the admin UI (Users > edit > username) or the REST user update endpoint, then retry.","Re-fetch the userId at call time from a username lookup (Users.findOneByUsernameIgnoringCase) instead of caching IDs.","If the user was deleted, choose another target or restore the account."],"exampleFix":"// before\nawait addRoomOwner(uid, rid, maybeDeletedUserId);\n\n// after\nconst target = await Users.findOneById(userId, { projection: { username: 1 } });\nif (!target?.username) throw new Error('target user missing or has no username');\nawait addRoomOwner(uid, rid, target._id);","handlingStrategy":"validation","validationCode":"const target = await Users.findOneById(userId, { projection: { username: 1 } });\nif (!target?.username) throw new Error('target user missing or has no username');","typeGuard":"const hasUsername = (u: { username?: string } | null): u is { username: string } =>\n  Boolean(u && typeof u.username === 'string' && u.username.length > 0);","tryCatchPattern":"try {\n  await addRoomOwner(uid, rid, userId);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {\n    // target userId wrong or account has no username; verify account data\n  }\n}","preventionTips":["Resolve targets by username at call time and pass the freshly fetched _id.","Alert on user documents without usernames — they break role operations and system messages.","Never feed IDs from external systems into method calls without a local existence check."],"tags":["meteor-method","users","validation","rooms"],"backgroundTag":"user-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}