{"record":{"id":"77db0526bffdc50e","repo":"HeyPuter/puter","slug":"password-mismatch","errorCode":"password_mismatch","errorMessage":"Incorrect password.","messagePattern":"Incorrect password\\.","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"src/backend/controllers/auth/AuthController.ts","lineNumber":433,"sourceCode":"        }\n        if (user.suspended) {\n            throw new HttpError(401, 'This account is suspended.', {\n                legacyCode: 'account_suspended',\n            });\n        }\n        if (user.password === null) {\n            throw new HttpError(401, 'Incorrect password.', {\n                legacyCode: 'unauthorized',\n            });\n        }\n\n        // Verify password\n        const passwordMatch = await bcrypt.compare(\n            password,\n            user.password as string,\n        );\n        if (!passwordMatch) {\n            throw new HttpError(401, 'Incorrect password.', {\n                legacyCode: 'password_mismatch',\n            });\n        }\n\n        const reauthAuthId = this.#extractAuthIdFromReauthToken(\n            req.body.reauth_token,\n        );\n        await this.#enforceAuthIdMatch(req, user, reauthAuthId);\n\n        // OTP branching — if 2FA enabled, return a short-lived OTP JWT.\n        // Re-bind the verified `auth_id` into the JWT so the follow-up\n        // OTP/recovery call can re-enforce the match without re-trusting\n        // a free-form claim from the client.\n        if (user.otp_enabled) {\n            const otpClaims: Record<string, unknown> = {\n                user_uid: user.uuid,\n                purpose: 'otp-login',\n            };","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/auth/AuthController.ts#L415-L451","documentation":"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.","triggerScenarios":"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.","commonSituations":"Forgotten password; stale cached credentials; password recently rotated; user confused between two accounts.","solutions":["Use the password-reset flow to set a new password.","Verify caps-lock and keyboard layout; retype the password.","Send the raw password string (not a client-side hash) — the server hashes via bcrypt."],"exampleFix":"// before: client pre-hashes the password\nawait fetch('/login', { method:'POST', body:JSON.stringify({ username, password: sha256(pwd) }) });\n\n// after: send the raw password, let the server bcrypt-compare\nawait fetch('/login', { method:'POST', body:JSON.stringify({ username, password: pwd }) });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await login(username, password); }\ncatch (e) {\n  if (e.code === 'password_mismatch') { /* show 'wrong password' + reset link */ }\n  else throw e;\n}","preventionTips":["Send the raw password, not a client-side hash.","Provide a password-reset link alongside the wrong-password error."],"tags":["auth","login","password","unauthorized","credentials"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}