Supabase rejects password updates where the new password string matches the existing one and responds with "same_password: New password must be different." The API re-authenticates the submitted password before writing, so the request finishes with HTTP 422 whenever both values align.
The Auth API inlines a comparison before it hashes and stores anything. When `params.Password` is present, Supabase calls `user.Authenticate` to see if the supplied password already matches the stored hash. If the call returns true it raises the `same_password` error and logs "New password should be different from the old password." The result is that the call fails before `user.SetPassword` ever runs, so repeated updates with the same string are deliberately blocked to keep the audit log and notifications coherent.
If you capture both the current and the new password, compare them before sending the request and show a clear message when they match. Example for a change-password flow with both fields:
if (newPassword === currentPassword) {
throw new Error("Please choose a different password before submitting.");
}
const { error } = await supabase.auth.updateUser({ password: newPassword });
if (error) throw error;This avoids the extra round-trip and lets you guide the user to a fresh value instead of triggering the server-side same_password rejection.
Password reset links do not send the old password back to the server, so rely on the UI to state that the user must pick a new string. Display the server message verbatim if it ever surfaces:
same_password: New password must be differentand remind them that reusing the drafted password, even if they remember it, will keep the update from succeeding. This reduces confusion when the server returns 422 because the submitted value matches their existing password.
When using the service-role key, check that the password you are applying differs from the stored value before running supabase.auth.admin.updateUserById. If in doubt, generate a cryptographically random string or rotate the account via an email reset. That prevents automation from hitting same_password while still letting you enforce password rotation.
Supabase's same_password check lives inside internal/api/user.go lines 150-185. After any required reauthentication it calls user.Authenticate with the new password and, if it matches, returns apierrors.ErrorCodeSamePassword with the literal "New password should be different from the old password." The error code list in internal/api/apierrors/errorcode.go defines the same_password identifier, so any client that sees that code can map it straight back to the comparison logic before a password hash is updated.
email_address_not_authorized: Email sending to this address is not authorized
Email address not authorized for sending in Supabase Auth
reauthentication_needed: Reauthentication required for security-sensitive actions
Reauthentication required for security-sensitive actions
no_authorization: No authorization header was provided
How to fix "no authorization header was provided" in Supabase
email_conflict_identity_not_deletable: Cannot delete identity because of email conflict
How to fix "Cannot delete identity because of email conflict" in Supabase
otp_expired: OTP has expired
How to fix 'otp_expired: OTP has expired' in Supabase