{"record":{"id":"4bb4270ba269e473","repo":"toeverything/AFFiNE","slug":"wrong-sign-in-credentials-4bb427","errorCode":"wrong_sign_in_credentials","errorMessage":"Wrong user email or password: ${email}","messagePattern":"Wrong user email or password: (.+?)","errorType":"error_code","errorClass":"WrongSignInCredentials","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/models/user.ts","lineNumber":146,"sourceCode":"  async getUserByEmail(\n    email: string,\n    filter: UserFilter = {}\n  ): Promise<User | null> {\n    const rows = await this.db.$queryRaw<User[]>`\n      SELECT id, name, email, password, registered, email_verified as \"emailVerifiedAt\", avatar_url as \"avatarUrl\", registered, created_at as \"createdAt\", disabled\n      FROM \"users\"\n      WHERE lower(\"email\") = lower(${email})\n      ${Prisma.raw(filter.withDisabled ? '' : 'AND disabled = false')}\n    `;\n\n    return rows[0] ?? null;\n  }\n\n  async signIn(email: string, password: string): Promise<User> {\n    const user = await this.getUserByEmail(email);\n\n    if (!user) {\n      throw new WrongSignInCredentials({ email });\n    }\n\n    if (!user.password) {\n      throw new WrongSignInMethod();\n    }\n\n    const passwordMatches = await this.crypto.verifyPassword(\n      password,\n      user.password\n    );\n\n    if (!passwordMatches) {\n      throw new WrongSignInCredentials({ email });\n    }\n\n    return user;\n  }\n","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/models/user.ts#L128-L164","documentation":"Thrown by UserModel.signIn (user.ts:146) when getUserByEmail returns null — i.e. no user matches the case-insensitive email, or the only match is a disabled account (getUserByEmail excludes disabled unless withDisabled:true). The message is deliberately identical to the wrong-password case so callers cannot enumerate which emails are registered. UserFriendlyError, code wrong_sign_in_credentials, type invalid_input, HTTP 400, data {email}.","triggerScenarios":"POST /sign-in (or UserModel.signIn) with an unregistered email, a disabled user's email, or a mistyped email.","commonSituations":"User mistypes their email; the account was disabled by an admin; testing against an environment where the user record was never seeded; user believes they registered but used a different address.","solutions":["Verify the email spelling and retry.","If unregistered, complete sign-up first.","If the account was disabled, ask an admin to re-enable it.","In the UI, show the same generic 'email or password incorrect' message as for a wrong password."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { WrongSignInCredentials } from '../base/error/errors.gen';\n\ntry {\n  const user = await models.user.signIn(email, password);\n  // success\n} catch (e) {\n  if (e instanceof WrongSignInCredentials) {\n    // show generic 'email or password incorrect'; do NOT reveal whether email exists\n  } else throw e;\n}","preventionTips":["Treat this identically to the wrong-password case in the UI to avoid email enumeration.","Offer a 'forgot password' / 'sign up' path from this error.","Trim email input before submitting."],"tags":["auth","signin","credentials"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}