{"record":{"id":"49c2bb7154fcef3d","repo":"Budibase/budibase","slug":"password-change-is-disabled-for-this-user","errorCode":null,"errorMessage":"Password change is disabled for this user","messagePattern":"Password change is disabled for this user","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/backend-core/src/users/db.ts","lineNumber":133,"sourceCode":"    opts: SaveUserOpts = {\n      hashPassword: true,\n      requirePassword: true,\n    },\n    tenantId: string,\n    dbUser?: any,\n    account?: Account\n  ): Promise<User> {\n    let { password, _id } = user\n\n    // don't require a password if the db user doesn't already have one\n    if (dbUser && !dbUser.password) {\n      opts.requirePassword = false\n    }\n\n    let hashedPassword\n    if (password && password !== dbUser?.password) {\n      if (await UserDB.isPreventPasswordActions(user, account)) {\n        throw new HTTPError(\"Password change is disabled for this user\", 400)\n      }\n\n      if (!opts.skipPasswordValidation) {\n        const passwordValidation = validatePassword(password)\n        if (!passwordValidation.valid) {\n          throw new HTTPError(passwordValidation.error, 400)\n        }\n      }\n\n      hashedPassword = opts.hashPassword ? await hash(password) : password\n    } else if (dbUser) {\n      hashedPassword = dbUser.password\n    }\n\n    // passwords are never required if sso is enforced\n    const requirePasswords =\n      opts.requirePassword && !(await UserDB.features.isSSOEnforced())\n    if (!hashedPassword && requirePasswords) {","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/users/db.ts#L115-L151","documentation":"buildUser throws an HTTPError(400) when a caller attempts to set or change a password for a user whose account is SSO-managed (isPreventPasswordActions returns true). SSO-authenticated users must change passwords via their identity provider, so Budibase blocks local password writes. This protects consistency between the local CouchDB user record and the external IdP.","triggerScenarios":"Calling save/buildUser/bulkCreate (via builtUser) with a `password` field that differs from the stored password on a user whose account is flagged SSO (isSSOUser or the tenant's account is an SSO account matching the user email).","commonSituations":"Admins trying to reset an SSO user's password from the admin UI or API; sync scripts bulk-updating users with password fields; self-hosted configs where SSO was enabled after password users existed; passing the full user object back to the save endpoint (echoing a stale password) instead of omitting it.","solutions":["Remove the password field from the update payload so the user keeps their existing/SSO-managed password","Have the user change their password in the SSO identity provider instead","Convert the user off SSO (or the tenant off SSO enforcement) before allowing local password changes","Pass opts.skipPasswordValidation is irrelevant here; instead check UserDB.isPreventPasswordActions before sending a password"],"exampleFix":"// before\nawait users.save({ _id: userId, password: \"newPass123\" })\n// after\n// omit password for SSO users\nconst update: any = { _id: userId }\nif (!(await UserDB.isPreventPasswordActions(user))) {\n  update.password = \"newPass123\"\n}\nawait users.save(update)","handlingStrategy":"try-catch","validationCode":"// pre-check before saving\nimport { UserDB } from \"@budibase/backend-core/users\"\nconst blocked = await UserDB.isPreventPasswordActions(user, account)\nif (blocked) throw new Error(\"User is SSO-managed; omit the password field\")","typeGuard":"function isSsoManaged(user: { ssoId?: string }): boolean {\n  return typeof user.ssoId === \"string\" && user.ssoId.length > 0\n}","tryCatchPattern":"try {\n  await users.save({ _id: userId, password: newPass })\n} catch (e: any) {\n  if (e?.status === 400 && e?.message === \"Password change is disabled for this user\") {\n    // handle SSO-managed user: notify admin / redirect to IdP\n  } else throw e\n}","preventionTips":["Omit the password field on updates unless the password actually changes","Detect SSO users (ssoId present) before sending password updates","Surface the message to admins with a pointer to configure the password in the IdP"],"tags":["authentication","sso","validation"],"backgroundTag":"password-change-blocked-sso-user","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}