infiniflow/ragflow · error · Exception
Same email: {user_info.email} exists!
Error message
Same email: {user_info.email} exists! What it means
Raised during OAuth registration when the query after user_register() returns more than one row for the same email — the user table contains duplicates, violating the single-account-per-email assumption. Registration is rolled back and the browser is redirected to /?error=Same email ... exists!.
Source
Thrown at api/apps/restful_apis/user_api.py:248
avatar = ""
users = user_register(
user_id,
{
"access_token": get_uuid(),
"email": user_info.email,
"avatar": avatar,
"nickname": user_info.nickname,
"login_channel": channel,
"last_login_time": get_format_time(),
"is_superuser": False,
},
)
if not users:
raise Exception(f"Failed to register {user_info.email}")
if len(users) > 1:
raise Exception(f"Same email: {user_info.email} exists!")
# Try to log in
user = users[0]
login_user(user)
return redirect(f"/?auth={user.get_id()}")
except Exception as e:
rollback_user_registration(user_id)
logging.exception(e)
return redirect(f"/?error={str(e)}")
# User exists, try to log in
user = users[0]
user.access_token = get_uuid()
if user and hasattr(user, "is_active") and user.is_active == "0":
return redirect("/?error=user_inactive")
login_user(user)View on GitHub (pinned to 554fb1133a)
Solutions
- Deduplicate the user table: SELECT email, COUNT(*) FROM user GROUP BY email HAVING COUNT(*)>1, then merge/remove the extra rows.
- Add/restore a unique constraint on user.email to prevent recurrence.
- If caused by concurrent callbacks, retry login after the first transaction commits — the existing-user path will then log in.
- Verify rollback_user_registration cleaned the half-inserted row.
Example fix
-- find duplicates SELECT email, COUNT(*) FROM user GROUP BY email HAVING COUNT(*) > 1; -- keep one row per email, delete the others, then: ALTER TABLE user ADD UNIQUE KEY uq_user_email (email);
Defensive patterns
Strategy: validation
Validate before calling
def email_unique(email):
users = UserService.query(email=email)
return len(users) <= 1
assert email_unique(user_info.email), f"duplicate rows for {user_info.email} - dedupe user table" Try / catch
try:
user = complete_oauth_registration(user_info)
except Exception as e:
if "Same email" in str(e):
users = UserService.query(email=user_info.email)
if users:
login_user(users[0]) # recover by logging into the existing account
else:
raise Prevention
- Enforce a unique index on user.email in every environment.
- After migrations, run a duplicate-email audit query.
- Serialize concurrent first-login attempts for the same email (lock or single-flight).
When it happens
Trigger: OAuth callback for a new email where the users lookup returns len>1: pre-existing duplicate rows in the user table (from historical bugs or manual inserts) for that email.
Common situations: Databases migrated from older versions that allowed duplicates, concurrent OAuth callbacks for the same new email racing the insert, or test fixtures creating users with the same email.
Related errors
- Failed to register {user_info.email}
- Register failed: {msg}
- Unsupported type: {channel_type}
- Failed to fetch github user info: {e}
- Failed to exchange authorization code for token: {e}
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/6bc1924aeebc6270.
Report an issue: GitHub.