Budibase/budibase · error

Cannot reset password.

Error message

Cannot reset password.

What it means

The worker's resetUpdate endpoint wraps the entire password-reset flow in a try/catch and, for security, re-throws any underlying failure as a 400 with either the original message or the generic fallback 'Cannot reset password.'. The real cause (invalid/expired reset code, user not found, CouchDB error) is intentionally hidden so attackers cannot probe which reset tokens are valid. Whenever you see this message it means an exception escaped the reset handler, not that the new password itself was rejected.

Source

Thrown at packages/worker/src/api/controllers/global/auth.ts:272

  }
}

/**
 * Perform the user password update if the provided reset code is valid.
 */
export const resetUpdate = async (
  ctx: Ctx<PasswordResetUpdateRequest, PasswordResetUpdateResponse>
) => {
  const { resetCode, password } = ctx.request.body
  try {
    await authSdk.resetUpdate(resetCode, password)
    ctx.body = {
      message: "password reset successfully.",
    }
  } catch (err: any) {
    console.warn(err)
    // hide any details of the error for security
    ctx.throw(400, err.message || "Cannot reset password.")
  }
}

// DATASOURCE

export const datasourcePreAuth = async (
  ctx: UserCtx<void, void>,
  next: Next
) => {
  const provider = ctx.params.provider
  const returnPath =
    typeof ctx.query.returnPath === "string" ? ctx.query.returnPath : undefined
  const { middleware } = require(`@budibase/backend-core`)
  const handler = middleware.datasource[provider]
  if (!handler) {
    ctx.throw(400, "Unsupported datasource provider")
  }

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Request a fresh password-reset email and use the new link promptly (codes are single-use and expire).
  2. Check worker logs for the console.warn(err) output to see the underlying cause that was hidden from the client.
  3. Verify Redis/invite cache connectivity on the worker; restart it if the cache is unreachable.
  4. For multi-tenant deployments, confirm the request includes the correct tenantId so the code is looked up in the right tenant DB.

Example fix

// before: reusing an expired link fails with 'Cannot reset password.'
fetch(`/api/global/auth/reset?code=${oldCode}`, { ... })
// after: fetch a new code, then reset
const { code } = await requestReset(email)
await resetPassword({ code, password: newPassword })
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side pre-check before calling reset
if (!code || !newPassword || newPassword.length < 8) {
  throw new Error("Reset code and a valid new password are required")
}

Try / catch

try {
  await api.resetPassword({ code, password })
} catch (e) {
  // 400 hides the real cause for security; treat as 'request a new reset email'
  notifyUser("Reset failed or link expired — please request a new reset email")
}

Prevention

When it happens

Trigger: POST to the worker password-reset endpoint (resetUpdate) where: the reset code stored in the invite cache is missing, expired or for a different tenant; cache.invite.updateCode throws; the target user cannot be found; or any other exception occurs inside the handler.

Common situations: User clicks an emailed reset link after the code expired or was already consumed; Redis/CouchDB outage while resolving the reset code; multi-tenant setups where the tenantId is not supplied so the code is looked up in the wrong tenant; stale email links pointing at a different environment.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/aea70ef86c7b1b66. Report an issue: GitHub.