makeplane/plane · warning · AuthenticationException
5102
5102
Error message
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP
What it means
Raised in MagicCodeProvider.initiate (magic_code.py:98) — the SIGN_UP counterpart of 51. Same trigger (data['current_attempt'] > 2 on the issue path) but raised when NO User exists for the email, signaling an unregistered email hitting its code-issue limit. Code 5102, payload {email: self.key} (note: uses self.key, not the cleaned email).
Source
Thrown at apps/api/plane/authentication/provider/credentials/magic_code.py:98
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)
else:
value = {"current_attempt": 0, "email": self.key, "token": token}
expiry = 600
ri.set(key, json.dumps(value), ex=expiry)
# Reset the verify-attempt counter so each newly issued token startsView on GitHub (pinned to 1c8a60f858)
Solutions
- Wait for the 600s TTL to expire so the Redis key clears, then request a fresh code.
- Verify the email is spelled correctly before requesting (a typo creates a throwaway unregistered entry).
- Admin can delete the 'magic_<email>' Redis key to reset the counter immediately.
Example fix
# before: bot spamming signup codes for unknown emails -> 5102 # redis-cli DEL magic:user@example.com # after: counter reset; a fresh code can be issued
Defensive patterns
Strategy: validation
Validate before calling
import json
from plane.settings.redis import redis_instance
def can_issue_magic_code_signup(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 == 5102:
tell_user_to_wait_or_verify_email(email=e.payload.get('email'))
else:
raise Prevention
- Validate the email format/existence before requesting signup codes.
- Rate-limit signup code requests per IP/email to discourage enumeration.
When it happens
Trigger: Repeated initiate() for an email with no User row, within the 600s Redis TTL, pushes current_attempt past 2; the existence check fails and AuthenticationException code 5102 is raised.
Common situations: Someone repeatedly requesting a signup magic code without completing it; a bot enumerating emails; a user who keeps typoing their email and resending.
Related errors
AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12).
Data as JSON: /api/errors/f826da60b37b14e9.
Report an issue: GitHub.