{"record":{"id":"3b7f8fc3304cd45c","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-username-3b7f8f","errorCode":"error-invalid-username","errorMessage":"Invalid username","messagePattern":"Invalid username","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/users/deleteUserOwnAccount.ts","lineNumber":52,"sourceCode":"\tconst user = await Users.findOneById(fromUserId);\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'deleteUserOwnAccount',\n\t\t});\n\t}\n\n\tif (user.services?.password && trim(user.services.password.bcrypt)) {\n\t\tconst result = await Accounts._checkPasswordAsync(user as Meteor.User, {\n\t\t\tdigest: password.toLowerCase(),\n\t\t\talgorithm: 'sha-256',\n\t\t});\n\t\tif (result.error) {\n\t\t\tthrow new Meteor.Error('error-invalid-password', 'Invalid password', {\n\t\t\t\tmethod: 'deleteUserOwnAccount',\n\t\t\t});\n\t\t}\n\t} else if (!user.username || SHA256(user.username) !== password.trim()) {\n\t\tthrow new Meteor.Error('error-invalid-username', 'Invalid username', {\n\t\t\tmethod: 'deleteUserOwnAccount',\n\t\t});\n\t}\n\n\tawait deleteUser(fromUserId, confirmRelinquish);\n\n\t// App IPostUserDeleted event hook\n\tawait Apps.self?.triggerEvent(AppEvents.IPostUserDeleted, { user });\n\n\treturn true;\n};\n\nMeteor.methods<ServerMethods>({\n\tasync deleteUserOwnAccount(password, confirmRelinquish) {\n\t\tmethodDeprecationLogger.method('deleteUserOwnAccount', '9.0.0', '/v1/users.deleteOwnAccount');\n\t\tcheck(password, String);\n\n\t\tconst uid = Meteor.userId();","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/deleteUserOwnAccount.ts#L34-L70","documentation":"The account has NO usable local password (services.password.bcrypt empty or absent — typical of OAuth/LDAP/SSO-created users), so verification falls back to comparing the supplied value against SHA256(user.username). The throw means the account has no username at all, or the supplied digest does not equal sha256-hex of the username.","triggerScenarios":"A passwordless (OAuth-only) account where the caller sends anything other than SHA256(username) as the password argument; or an SSO account that never got a username set (!user.username short-circuits the check).","commonSituations":"Google/CAS/GitHub SSO users trying the password-user delete flow with their SSO password; custom clients that always send a password digest; username-less bot or application accounts.","solutions":["For passwordless accounts, send SHA256(user.username) hex as the password argument","Ensure the account actually has a username; OAuth users without one cannot pass this check — set a username first","Migrate to the REST endpoint /v1/users.deleteOwnAccount (the method is deprecated since 9.0.0) and follow its documented credential contract"],"exampleFix":"// before — SSO user sends their SSO password digest\nawait Meteor.callAsync('deleteUserOwnAccount', SHA256(ssoPassword).toString(), false);\n\n// after — passwordless accounts verify against sha256(username)\nconst digest = SHA256(currentUser.username).toString();\nawait Meteor.callAsync('deleteUserOwnAccount', digest, false);","handlingStrategy":"try-catch","validationCode":"// pick the credential the server will verify for this account type\nconst hasPassword = Boolean(user?.services?.password?.bcrypt);\nconst digest = SHA256(hasPassword ? password : user!.username!).toString();\nawait Meteor.callAsync('deleteUserOwnAccount', digest, false);","typeGuard":"const hasLocalPassword = (u: { services?: { password?: { bcrypt?: string } } } | null): boolean =>\n\tBoolean(u?.services?.password?.bcrypt && u.services.password.bcrypt.trim());","tryCatchPattern":"try {\n\tawait Meteor.callAsync('deleteUserOwnAccount', digest, false);\n} catch (err) {\n\tif ((err as { error?: string }).error === 'error-invalid-username') {\n\t\t// passwordless account: digest must equal sha256(username) — or account has no username\n\t}\n}","preventionTips":["Branch the delete flow on whether the account has services.password.bcrypt","For OAuth/SSO accounts, send sha256(username) — not the SSO password","Ensure OAuth provisioned accounts always get a username at creation"],"tags":["meteor","oauth","sso","account-deletion","username"],"backgroundTag":"invalid-credentials","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}