{"record":{"id":"de90150c93b7b8d0","repo":"makeplane/plane","slug":"5090","errorCode":"5090","errorMessage":"INVALID_MAGIC_CODE_SIGN_IN","messagePattern":"INVALID_MAGIC_CODE_SIGN_IN","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"warning","filePath":"apps/api/plane/authentication/provider/credentials/magic_code.py","lineNumber":187,"sourceCode":"                if verify_attempts >= self.MAX_VERIFY_ATTEMPTS:\n                    # Invalidate the token (and counter) so further attempts\n                    # must regenerate; regeneration is itself attempt-counted.\n                    ri.delete(self.key)\n                    ri.delete(self._verify_attempts_key(self.key))\n                    if user_exists:\n                        raise AuthenticationException(\n                            error_code=AUTHENTICATION_ERROR_CODES[\"EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN\"],\n                            error_message=\"EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN\",\n                            payload={\"email\": str(email)},\n                        )\n                    raise AuthenticationException(\n                        error_code=AUTHENTICATION_ERROR_CODES[\"EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP\"],\n                        error_message=\"EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP\",\n                        payload={\"email\": str(email)},\n                    )\n\n                if user_exists:\n                    raise AuthenticationException(\n                        error_code=AUTHENTICATION_ERROR_CODES[\"INVALID_MAGIC_CODE_SIGN_IN\"],\n                        error_message=\"INVALID_MAGIC_CODE_SIGN_IN\",\n                        payload={\"email\": str(email)},\n                    )\n                else:\n                    raise AuthenticationException(\n                        error_code=AUTHENTICATION_ERROR_CODES[\"INVALID_MAGIC_CODE_SIGN_UP\"],\n                        error_message=\"INVALID_MAGIC_CODE_SIGN_UP\",\n                        payload={\"email\": str(email)},\n                    )\n        else:\n            email = str(self.key).replace(\"magic_\", \"\", 1)\n            if User.objects.filter(email=email).exists():\n                raise AuthenticationException(\n                    error_code=AUTHENTICATION_ERROR_CODES[\"EXPIRED_MAGIC_CODE_SIGN_IN\"],\n                    error_message=\"EXPIRED_MAGIC_CODE_SIGN_IN\",\n                    payload={\"email\": str(email)},\n                )","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/authentication/provider/credentials/magic_code.py#L169-L205","documentation":"Raised in MagicCodeProvider.set_user_data (magic_code.py:187) on the verify path when the submitted code is wrong, the verify budget is NOT yet exhausted, AND the email belongs to an existing User. Code 5090, payload {email}. This is the non-terminal wrong-code error (the user still has attempts remaining).","triggerScenarios":"A valid token exists in Redis (key self.key) but str(token) != str(self.code). The verify counter is incremented atomically; if under MAX_VERIFY_ATTEMPTS and a User exists, AuthenticationException code 5090 is raised. The token stays valid for further attempts.","commonSituations":"Typo in the 6-digit code, code read from a delayed/truncated email, autofill of a stale code, or transposed digits.","solutions":["Re-enter the code carefully from the most recent email.","If unsure, wait and re-read the latest magic-code email (older emails' codes are invalid once a new token is issued).","Track remaining attempts client-side; regenerate before hitting MAX_VERIFY_ATTEMPTS to avoid lockout (5100)."],"exampleFix":"// before: wrong 6-digit code, user exists -> 5090 (token still valid)\n// after: submit the exact 6 digits from the newest email","handlingStrategy":"try-catch","validationCode":"from plane.authentication.provider.credentials.magic_code import MagicCodeProvider\nfrom plane.settings.redis import redis_instance\n\ndef verify_budget_remaining(token_key: str) -> int:\n    ri = redis_instance()\n    raw = ri.get(MagicCodeProvider._verify_attempts_key(token_key))\n    used = int(raw) if raw else 0\n    return max(MagicCodeProvider.MAX_VERIFY_ATTEMPTS - used, 0)","typeGuard":null,"tryCatchPattern":"try:\n    provider.set_user_data()\nexcept AuthenticationException as e:\n    if e.error_code == 5090:\n        show_remaining_attempts_and_re_prompt(email=e.payload.get('email'))\n    else:\n        raise","preventionTips":["Always read the code from the newest email.","Display remaining verify attempts to the user."],"tags":["authentication","magic-code","invalid-code","signin"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}