langgenius/dify · error · EmailAlreadyInUseError

email_already_in_use

email_already_in_use

Error message

A user with this email already exists.

What it means

Raised by EmailAlreadyInUseError in EmailRegisterResetApi.post after the token is validated and revoked, when AccountService.get_account_by_email_with_case_fallback finds an existing account for that email. The case-insensitive lookup means differing capitalization does not bypass it. The token has already been revoked at this point, so the flow cannot be retried with the same token.

Source

Thrown at api/controllers/console/auth/email_register.py:185

        # Validate token and get register data
        register_data = AccountService.get_email_register_data(req_data.token)
        if not register_data:
            raise InvalidTokenError()
        # Must use token in reset phase
        if register_data.get("phase", "") != "register":
            raise InvalidTokenError()

        # Revoke token to prevent reuse
        AccountService.revoke_email_register_token(req_data.token)

        email = register_data.get("email", "")
        normalized_email = email.lower()

        account = AccountService.get_account_by_email_with_case_fallback(email, session=db.session())

        if account:
            raise EmailAlreadyInUseError()

        account = self._create_new_account(
            email=normalized_email,
            password=req_data.password_confirm,
            timezone=req_data.timezone,
            language=req_data.language,
        )
        token_pair = AccountService.login(account=account, session=db.session(), ip_address=extract_remote_ip(request))
        AccountService.reset_login_error_rate_limit(normalized_email)

        return {"result": "success", "data": token_pair.model_dump()}

    def _create_new_account(
        self,
        email: str,
        password: str,
        timezone: str | None = None,
        language: str | None = None,

View on GitHub (pinned to ef8544b173)

Solutions

  1. If the user owns the account, direct them to login or forgot-password instead of registration.
  2. Restart email-send only if the email genuinely should be new; otherwise the account exists.
  3. Add a pre-check (e.g., an existence probe) before starting registration to fail fast.
  4. Handle the 'email_already_in_use' code in the UI with a link to the login flow.

Example fix

// before
register({ token, ... }); // user already has account
// after
if (res.code === 'email_already_in_use') {
  router.push('/signin?email=' + encodeURIComponent(email));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Optional pre-check if an existence probe exists; otherwise rely on try-catch
if (await accountExists(email)) {
  redirect('/signin?email=' + encodeURIComponent(email));
  return;
}

Try / catch

try {
  await register({ token, ... });
} catch (e) {
  if (e.code === 'email_already_in_use') redirect('/signin');
  else throw e;
}

Prevention

When it happens

Trigger: POST /console/api/email-register where an account already exists for the email (case-insensitive). The user completed verification but the email was registered by someone else (or themselves in another session) in the meantime.

Common situations: Two browser tabs both registering; user forgot they already have an account; race between concurrent registrations; email alias that case-folds onto an existing account; previous failed registration that actually created the account.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/ba778d80c01f3240. Report an issue: GitHub.