{"record":{"id":"65450213e4d98f20","repo":"infiniflow/ragflow","slug":"exist-more-than-1-user-username","errorCode":null,"errorMessage":"Exist more than 1 user: {username}!","messagePattern":"Exist more than 1 user: (.+?)!","errorType":"http","errorClass":"AdminException","httpStatus":400,"severity":"critical","filePath":"admin/server/services.py","lineNumber":106,"sourceCode":"            raise UserAlreadyExistsError(username)\n        # Construct user info data\n        user_info_dict = {\n            \"email\": username,\n            \"nickname\": \"\",  # ask user to edit it manually in settings.\n            \"password\": decrypt(password),\n            \"login_channel\": \"password\",\n            \"is_superuser\": role == \"admin\",\n        }\n        return create_new_user(user_info_dict)\n\n    @staticmethod\n    def delete_user(username):\n        # use email to delete\n        user_list = UserService.query_user_by_email(username)\n        if not user_list:\n            raise UserNotFoundError(username)\n        if len(user_list) > 1:\n            raise AdminException(f\"Exist more than 1 user: {username}!\")\n        usr = user_list[0]\n        return delete_user_data(usr.id)\n\n    @staticmethod\n    def update_user_password(username, new_password) -> str:\n        # use email to find user. check exist and unique.\n        user_list = UserService.query_user_by_email(username)\n        if not user_list:\n            raise UserNotFoundError(username)\n        elif len(user_list) > 1:\n            raise AdminException(f\"Exist more than 1 user: {username}!\")\n        # check new_password different from old.\n        usr = user_list[0]\n        psw = decrypt(new_password)\n        # SSO-provisioned users (OIDC/OAuth) have no local password (usr.password is None):\n        # skip the equality check, which would otherwise crash inside werkzeug's split().\n        if usr.password and check_password_hash(usr.password, psw):\n            return \"Same password, no need to update!\"","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/admin/server/services.py#L88-L124","documentation":"AdminException (HTTP 400) raised by UserMgr.delete_user (admin/server/services.py:106) when query_user_by_email returns more than one row. Because deletion acts on user_list[0] only, ambiguity is refused rather than guessing. Duplicate email rows indicate a broken uniqueness constraint or manual DB edits.","triggerScenarios":"Two or more user rows share the same email in the database; typically after imports, race-condition double-creates before a unique index existed, or direct SQL inserts bypassing the app's checks.","commonSituations":"Upgraded installations where the email unique index was never added; concurrent SSO first-login provisioning creating the same account twice; data restored/merged from another environment.","solutions":["Inspect duplicates: SELECT id, email, create_date FROM user WHERE email = '<username>';","Delete or merge the surplus rows by explicit id so exactly one remains.","Add/repair a unique constraint on the email column to prevent recurrence.","Retry the admin delete call once the table is consistent."],"exampleFix":"-- before: table has duplicates, admin delete returns 400\nSELECT id, email FROM user WHERE email = 'user@example.com';\n-- after: keep newest row, remove the rest\nDELETE FROM user WHERE email = 'user@example.com' AND id NOT IN (\n  SELECT id FROM (SELECT id FROM user WHERE email = 'user@example.com' ORDER BY create_date DESC LIMIT 1) t\n);\nALTER TABLE user ADD UNIQUE KEY uq_user_email (email);","handlingStrategy":"validation","validationCode":"from api.db.services import UserService\n\ndef assert_single_user(email: str) -> None:\n    users = UserService.query_user_by_email(email)\n    if len(users) != 1:\n        raise RuntimeError(f'expected exactly 1 user for {email}, got {len(users)}')","typeGuard":null,"tryCatchPattern":"from admin.server.exceptions import AdminException\ntry:\n    UserMgr.delete_user(email)\nexcept AdminException as e:\n    if 'more than 1 user' in e.message.lower():\n        raise RuntimeError(f'duplicate rows for {email}; run DB dedup first') from e\n    raise","preventionTips":["Monitor the user table for duplicate emails: SELECT email, COUNT(*) FROM user GROUP BY email HAVING COUNT(*) > 1;","Keep a unique index on the email column after every upgrade.","Never insert user rows via raw SQL; always go through the service layer."],"tags":["data-integrity","duplicate-users","admin-api","delete"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}