{"record":{"id":"7d190036b2e9d2c1","repo":"toeverything/AFFiNE","slug":"wrong-sign-in-credentials-7d1900","errorCode":"wrong_sign_in_credentials","errorMessage":"Wrong user email or password: ${email}","messagePattern":"Wrong user email or password: (.+?)","errorType":"exception","errorClass":"WrongSignInCredentials","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/core/auth/magic-link.ts","lineNumber":62,"sourceCode":"\n    const callbackUrlObj = this.url.url(callbackUrl);\n    const redirectUriInCallback =\n      callbackUrlObj.searchParams.get('redirect_uri');\n    if (\n      redirectUriInCallback &&\n      !this.url.isAllowedRedirectUri(redirectUriInCallback)\n    ) {\n      throw new ActionForbidden();\n    }\n\n    const user = await this.models.user.getUserByEmail(email, {\n      withDisabled: true,\n    });\n\n    if (!user) {\n      await this.assertSignupAllowed(email);\n    } else if (user.disabled) {\n      throw new WrongSignInCredentials({ email });\n    }\n\n    const ttlInSec = 30 * 60;\n    const { token, expiresAt: tokenExpiresAt } =\n      await this.models.verificationToken.createWithExpiresAt(\n        TokenType.SignIn,\n        email,\n        ttlInSec\n      );\n\n    const otp = this.crypto.otp();\n    const { expiresAt: otpExpiresAt } = await this.models.magicLinkOtp.upsert(\n      email,\n      otp,\n      token,\n      clientNonce\n    );\n","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/core/auth/magic-link.ts#L44-L80","documentation":"While sending a magic link, MagicLinkService.load looks the user up with withDisabled: true; if the account exists but is flagged disabled, it throws WrongSignInCredentials (wrong_sign_in_credentials) - the same error as a wrong password, deliberately, so callers cannot distinguish 'disabled account' from 'bad credentials' for enumeration reasons. The disabled user never receives the email.","triggerScenarios":"A deactivated/banned user (or one disabled by an admin) requests a magic-link sign-in; user was disabled during workspace cleanup but still has the app open; admin disabled the account and the user tries the passwordless flow instead of password.","commonSituations":"Offboarded employees retrying sign-in; self-hosted admins disabling test accounts; SSO provisioning disabling local accounts; users confused because the same error also appears for a genuinely wrong email/password.","solutions":["An administrator must re-enable the account in user management before sign-in can proceed","If you own the instance, check the user's disabled flag in the admin UI / database","Sign in with a different, active account","Do not brute-force variants of the email - the error intentionally does not confirm the account's state"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isWrongSignInCredentials(e: unknown): boolean {\n  return typeof e === 'object' && e !== null && (e as { code?: string }).code === 'wrong_sign_in_credentials';\n}","tryCatchPattern":"try {\n  await sendMagicLink(email);\n} catch (e) {\n  if (isWrongSignInCredentials(e)) {\n    show('Email or password is incorrect, or this account is not active.'); // do not probe further\n  } else throw e;\n}","preventionTips":["Show one generic message for wrong_sign_in_credentials; never branch on account state","Admins: verify the disabled flag before escalating user reports"],"tags":["auth","magic-link","account-disabled","sign-in"],"backgroundTag":"user-account-disabled","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}