Budibase/budibase · error · HTTPError
Password change is disabled for this user
Error message
Password change is disabled for this user
What it means
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.
Source
Thrown at packages/backend-core/src/users/db.ts:133
opts: SaveUserOpts = {
hashPassword: true,
requirePassword: true,
},
tenantId: string,
dbUser?: any,
account?: Account
): Promise<User> {
let { password, _id } = user
// don't require a password if the db user doesn't already have one
if (dbUser && !dbUser.password) {
opts.requirePassword = false
}
let hashedPassword
if (password && password !== dbUser?.password) {
if (await UserDB.isPreventPasswordActions(user, account)) {
throw new HTTPError("Password change is disabled for this user", 400)
}
if (!opts.skipPasswordValidation) {
const passwordValidation = validatePassword(password)
if (!passwordValidation.valid) {
throw new HTTPError(passwordValidation.error, 400)
}
}
hashedPassword = opts.hashPassword ? await hash(password) : password
} else if (dbUser) {
hashedPassword = dbUser.password
}
// passwords are never required if sso is enforced
const requirePasswords =
opts.requirePassword && !(await UserDB.features.isSSOEnforced())
if (!hashedPassword && requirePasswords) {View on GitHub (pinned to a81a902e9a)
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
Example fix
// before
await users.save({ _id: userId, password: "newPass123" })
// after
// omit password for SSO users
const update: any = { _id: userId }
if (!(await UserDB.isPreventPasswordActions(user))) {
update.password = "newPass123"
}
await users.save(update) Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check before saving
import { UserDB } from "@budibase/backend-core/users"
const blocked = await UserDB.isPreventPasswordActions(user, account)
if (blocked) throw new Error("User is SSO-managed; omit the password field") Type guard
function isSsoManaged(user: { ssoId?: string }): boolean {
return typeof user.ssoId === "string" && user.ssoId.length > 0
} Try / catch
try {
await users.save({ _id: userId, password: newPass })
} catch (e: any) {
if (e?.status === 400 && e?.message === "Password change is disabled for this user") {
// handle SSO-managed user: notify admin / redirect to IdP
} else throw e
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Configuration invalid. Must contain google clientID and clie
- Configuration invalid. Must contain clientID, clientSecret,
- ${passwordValidation.error}
- Email is required
- A new verification key is required when changing the embed S
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/49c2bb7154fcef3d.
Report an issue: GitHub.