{"record":{"id":"af7bd14230193c58","repo":"odysseus-dev/odysseus","slug":"current-password-is-incorrect","errorCode":null,"errorMessage":"Current password is incorrect","messagePattern":"Current password is incorrect","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/auth_routes.py","lineNumber":210,"sourceCode":"            pass\n        return result\n\n    @router.get(\"/policy\")\n    async def auth_policy():\n        \"\"\"Return public auth policy constants for the frontend.\"\"\"\n        return auth_manager.policy()\n\n    @router.post(\"/change-password\")\n    async def change_password(body: ChangePasswordRequest, request: Request):\n        user = _get_current_user(request)\n        if not user:\n            raise HTTPException(401, \"Not authenticated\")\n        if len(body.new_password) < PASSWORD_MIN_LENGTH:\n            raise HTTPException(400, f\"Password must be at least {PASSWORD_MIN_LENGTH} characters\")\n        current_token = request.cookies.get(SESSION_COOKIE)\n        ok = await asyncio.to_thread(auth_manager.change_password, user, body.current_password, body.new_password)\n        if not ok:\n            raise HTTPException(400, \"Current password is incorrect\")\n        await asyncio.to_thread(auth_manager.revoke_user_sessions, user, current_token)\n        return {\"ok\": True}\n\n    # ------------------------------------------------------------------\n    # Two-factor authentication\n    # ------------------------------------------------------------------\n\n    @router.post(\"/2fa/setup\")\n    async def totp_setup(request: Request):\n        \"\"\"Generate a TOTP secret and return the QR code URI.\"\"\"\n        user = _get_current_user(request)\n        if not user:\n            raise HTTPException(401, \"Not authenticated\")\n        if auth_manager.totp_enabled(user):\n            raise HTTPException(400, \"2FA is already enabled\")\n        secret = auth_manager.totp_generate_secret(user)\n        if not secret:\n            raise HTTPException(500, \"Failed to generate secret\")","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/auth_routes.py#L192-L228","documentation":"Raised as HTTP 400 by POST /change-password when auth_manager.change_password(user, current_password, new_password) returns falsy. The auth manager re-verifies the current password before rotating the hash; a mismatch (or an internal failure to update) yields falsy. This is the 'prove you own the account' step for password rotation.","triggerScenarios":"Sending a wrong current_password while authenticated; sending an empty current_password; or a user record whose stored hash can't be verified after a hashing-scheme migration (indistinguishable from wrong password at the route level).","commonSituations":"Password managers auto-filling the NEW password into the CURRENT field, users forgetting which password is active after a recent change, or post-migration legacy hashes that verify_password can't read.","solutions":["Re-enter the current (old) password exactly — beware autofill putting the new password in the wrong field.","Clear saved credentials for the site in the password manager, then retry.","If the old password is genuinely forgotten, use the reset flow / admin reset instead of this endpoint.","If ALL users fail after an upgrade, re-hash stored passwords or restore verify compatibility with the old scheme."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Guard against autofill putting the NEW password in the CURRENT field\nif (currentPassword === newPassword) warn('Current and new passwords look identical — check autofill');","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.status === 400 && /current password/i.test(e.message)) focusField('current_password'); }","preventionTips":["Name autofill attributes correctly: autocomplete='current-password' vs 'new-password'.","Clear stale credentials for the site in the password manager.","If the old password is unknown, use the reset flow rather than guessing."],"tags":["auth","http-400","password-change","autofill","fastapi"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}