makeplane/plane · warning · AuthenticationException

5100

5100

Error message

EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN

What it means

Raised in MagicCodeProvider.initiate (magic_code.py:92) when the rate limit on issuing magic codes is exceeded for an email. The Redis key 'magic_'+email holds {current_attempt, email, token}. When an existing key has data['current_attempt'] > 2 AND a User with that email exists, code 5100 (SIGN_IN variant) is raised with payload {email}. This guards the issue path, not the verify path.

Solutions

  1. Wait for the Redis key to expire (TTL 600s) or have the user slow down resend requests.
  2. Throttle the client-side 'resend' button (e.g., 60s cooldown) to stay under the 3-issue budget.
  3. If legitimately locked, an admin can delete the 'magic_<email>' Redis key to reset the counter.

Example fix

// before: client auto-resends on every focus -> current_attempt > 2 -> 5100
// after: client enforces a 60s resend cooldown and stops at 3 sends
Defensive patterns

Strategy: validation

Validate before calling

import json
from plane.settings.redis import redis_instance

def can_issue_magic_code(email: str) -> bool:
    ri = redis_instance()
    key = 'magic_' + str(email)
    if not ri.exists(key):
        return True
    return json.loads(ri.get(key)).get('current_attempt', 0) <= 2

Try / catch

try:
    provider.initiate()
except AuthenticationException as e:
    if e.error_code == 5100:
        tell_user_to_wait_then_retry(email=e.payload.get('email'))
    else:
        raise

Prevention

When it happens

Trigger: Calling initiate() repeatedly for the same email: each call increments current_attempt. Once it exceeds 2 (i.e., the 4th+ request within the 600s TTL), the existence check decides SIGN_IN vs SIGN_UP. Existing user -> 5100. Note the off-by-one: the check uses the pre-increment value, so the limit triggers a step later than the counter name implies.

Common situations: User spamming 'resend code', a misbehaving client auto-retrying, or an attacker probing the magic-code flow for a known email.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/5a7e1392c4d0a105. Report an issue: GitHub.

Appendix: source

Thrown at apps/api/plane/authentication/provider/credentials/magic_code.py:92

    def initiate(self):
        ## Generate a random token
        token = str(secrets.randbelow(900000) + 100000)

        ri = redis_instance()

        key = "magic_" + str(self.key)

        # Check if the key already exists in python
        if ri.exists(key):
            data = json.loads(ri.get(key))

            current_attempt = data["current_attempt"] + 1

            if data["current_attempt"] > 2:
                email = str(self.key).replace("magic_", "", 1)
                if User.objects.filter(email=email).exists():
                    raise AuthenticationException(
                        error_code=AUTHENTICATION_ERROR_CODES["EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN"],
                        error_message="EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN",
                        payload={"email": str(email)},
                    )
                else:
                    raise AuthenticationException(
                        error_code=AUTHENTICATION_ERROR_CODES["EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP"],
                        error_message="EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP",
                        payload={"email": self.key},
                    )

            value = {
                "current_attempt": current_attempt,
                "email": str(self.key),
                "token": token,
            }
            expiry = 600
            ri.set(key, json.dumps(value), ex=expiry)

View on GitHub (pinned to 1c8a60f858)