{"record":{"id":"bcff3c81df9ed840","repo":"infiniflow/ragflow","slug":"email-and-password-do-not-match","errorCode":null,"errorMessage":"Email and password do not match!","messagePattern":"Email and password do not match!","errorType":"http","errorClass":"AdminException","httpStatus":400,"severity":"error","filePath":"admin/server/auth.py","lineNumber":163,"sourceCode":"            raise AdminException(f\"User {current_user.email} inactive\", 403)\n\n        return func(*args, **kwargs)\n\n    return wrapper\n\n\ndef login_admin(email: str, password: str):\n    \"\"\"\n    :param email: admin email\n    :param password: string before decrypt (RSA encrypted + base64 encoded)\n    \"\"\"\n    users = UserService.query(email=email)\n    if not users:\n        raise UserNotFoundError(email)\n    decrypted = decrypt(password)\n    user = UserService.query_user(email, decrypted)\n    if not user:\n        raise AdminException(\"Email and password do not match!\")\n    if not user.is_superuser:\n        raise AdminException(\"Not admin\", 403)\n    if user.is_active == ActiveEnum.INACTIVE.value:\n        raise AdminException(f\"User {email} inactive\", 403)\n\n    resp = user.to_json()\n    user.access_token = get_uuid()\n    login_user(user)\n    user.update_time = (current_timestamp(),)\n    user.update_date = (datetime_format(datetime.now()),)\n    user.last_login_time = get_format_time()\n    user.save()\n    msg = \"Welcome back!\"\n    return sync_construct_response(data=resp, auth=user.get_id(), message=msg)\n\n\ndef check_admin(username: str, password: str):\n    users = UserService.query(email=username)","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/admin/server/auth.py#L145-L181","documentation":"AdminException raised in login_admin (admin/server/auth.py:163) when the email exists but UserService.query_user(email, decrypt(password)) returns nothing — the RSA-decrypted, base64-decoded password does not match the stored one. This is the classic bad-credential error for the admin login endpoint, thrown only after the account lookup succeeded.","triggerScenarios":"POST /admin/login with the right email and a wrong password; sending a password that was not RSA-encrypted+base64-encoded the way the client/server pair expects (decrypt() yields garbage, so query_user misses); password changed in DB or via UI while an old credential file is still used.","commonSituations":"Using the default admin/admin after the password was already rotated; scripts that store the plaintext or differently-encoded password; frontend/CLI encryption mismatch after a RAGFlow upgrade changed the RSA key handling in api.utils.crypt.","solutions":["Retry with the correct password, encrypted exactly like the frontend/ragflow_cli does (RSA encrypt + base64) — see the contract documented in admin/client/user.py.","If locked out, reset the stored hash in the DB to encode_to_base64('admin') to restore the default credential, then change it after login.","Verify you are not hitting /auth/login (regular flow) with admin-flow encrypted credentials or vice versa."],"exampleFix":"-- emergency reset to the default password 'admin' (base64)\nUPDATE user SET password = TO_BASE64('admin') WHERE email = 'admin@ragflow.io';","handlingStrategy":"try-catch","validationCode":"# verify credentials the same way the server does, without the admin flow\nfrom api.utils.crypt import decrypt\nfrom api.db.services import UserService\nif not UserService.query_user(email, decrypt(encrypted_password)):\n    raise PermissionError(\"email/password mismatch; will raise 'Email and password do not match!' on login\")","typeGuard":null,"tryCatchPattern":"from api.common.exceptions import AdminException\nfor attempt_credential in candidates:\n    try:\n        session = login_admin(email, attempt_credential)\n        break\n    except AdminException as e:\n        if \"do not match\" not in str(e):\n            raise  # only retry on bad password, not on Not admin/inactive\nelse:\n    raise RuntimeError(\"all candidate passwords rejected\")","preventionTips":["Encrypt passwords exactly as the frontend/ragflow_cli does (RSA + base64) — see admin/client/user.py contract note.","Rotate the default admin/admin immediately after bootstrap and store it in a secret manager.","Distinguish unknown-email (UserNotFoundError) from wrong-password (this) when debugging logins."],"tags":["authentication","login","bad-password","admin"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}