HeyPuter/puter · error · HttpError

password_mismatch

password_mismatch

Error message

Incorrect password.

What it means

Returned by POST /login when bcrypt.compare(password, user.password) returns false — the password is syntactically valid and the account has a password hash, but the supplied password does not match it. The legacy code 'password_mismatch' distinguishes a wrong password from the no-password (unauthorized) and suspended (account_suspended) cases. All three return HTTP 401.

Source

Thrown at src/backend/controllers/auth/AuthController.ts:433

        }
        if (user.suspended) {
            throw new HttpError(401, 'This account is suspended.', {
                legacyCode: 'account_suspended',
            });
        }
        if (user.password === null) {
            throw new HttpError(401, 'Incorrect password.', {
                legacyCode: 'unauthorized',
            });
        }

        // Verify password
        const passwordMatch = await bcrypt.compare(
            password,
            user.password as string,
        );
        if (!passwordMatch) {
            throw new HttpError(401, 'Incorrect password.', {
                legacyCode: 'password_mismatch',
            });
        }

        const reauthAuthId = this.#extractAuthIdFromReauthToken(
            req.body.reauth_token,
        );
        await this.#enforceAuthIdMatch(req, user, reauthAuthId);

        // OTP branching — if 2FA enabled, return a short-lived OTP JWT.
        // Re-bind the verified `auth_id` into the JWT so the follow-up
        // OTP/recovery call can re-enforce the match without re-trusting
        // a free-form claim from the client.
        if (user.otp_enabled) {
            const otpClaims: Record<string, unknown> = {
                user_uid: user.uuid,
                purpose: 'otp-login',
            };

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Use the password-reset flow to set a new password.
  2. Verify caps-lock and keyboard layout; retype the password.
  3. Send the raw password string (not a client-side hash) — the server hashes via bcrypt.

Example fix

// before: client pre-hashes the password
await fetch('/login', { method:'POST', body:JSON.stringify({ username, password: sha256(pwd) }) });

// after: send the raw password, let the server bcrypt-compare
await fetch('/login', { method:'POST', body:JSON.stringify({ username, password: pwd }) });
Defensive patterns

Strategy: try-catch

Try / catch

try { await login(username, password); }
catch (e) {
  if (e.code === 'password_mismatch') { /* show 'wrong password' + reset link */ }
  else throw e;
}

Prevention

When it happens

Trigger: User typed the wrong password; caps-lock or layout issue; password was changed recently; client sent an old/hashed password instead of the raw password.

Common situations: Forgotten password; stale cached credentials; password recently rotated; user confused between two accounts.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/77db0526bffdc50e. Report an issue: GitHub.