{"record":{"id":"b490d3ea0b796cfc","repo":"toeverything/AFFiNE","slug":"wrong-sign-in-method","errorCode":"wrong_sign_in_method","errorMessage":"You are trying to sign in by a different method than you signed up with.","messagePattern":"You are trying to sign in by a different method than you signed up with\\.","errorType":"exception","errorClass":"WrongSignInMethod","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/models/user.ts","lineNumber":150,"sourceCode":"    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\n  async getPublicUserByEmail(email: string): Promise<PublicUser | null> {\n    const rows = await this.db.$queryRaw<PublicUser[]>`\n      SELECT id, name, avatar_url as \"avatarUrl\"\n      FROM \"users\"","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/models/user.ts#L132-L168","documentation":"WrongSignInMethod, thrown by UserModel.signIn (user.ts:150-152) when the email resolves to a user but that user's password column is null - the account was created through a different sign-in method (e.g. OAuth) and has no password to verify. The message tells the user they are trying a different method than the one they signed up with.","triggerScenarios":"signIn(email, password) for a user whose password is null: OAuth-registered accounts, or instances where the password hash was never set or was lost in migration.","commonSituations":"User signs up with Google and later tries email+password; password migration dropped hashes; the same email used for both OAuth and local signup flows.","solutions":["Sign in with the original provider (OAuth) instead of password","Attach a password via the set/reset-password flow, then retry","Branch before calling signIn when the account has no password and route to the provider flow"],"exampleFix":"// before\nawait user.signIn(email, password); // throws wrong_sign_in_method\n\n// after\nconst existing = await user.getUserByEmail(email);\nif (existing && !existing.password) {\n  // route to the OAuth sign-in flow for this account\n} else {\n  await user.signIn(email, password);\n}","handlingStrategy":"fallback","validationCode":"const existing = await user.getUserByEmail(email);\nif (existing && !existing.password) {\n  // route to the OAuth provider this account was created with\n} else {\n  await user.signIn(email, password);\n}","typeGuard":"const isPasswordlessUser = (\n  u: { password?: string | null } | null\n): u is { password: null } => !!u && !u.password;","tryCatchPattern":"try {\n  await user.signIn(email, password);\n} catch (e) {\n  if (e instanceof WrongSignInMethod) {\n    // fall back to the provider sign-in flow for this account\n  }\n  throw e;\n}","preventionTips":["Store the sign-in method on the account and branch before password auth","Offer 'continue with provider' when the account has no password","After OAuth signup, let users set a password if they also want password login"],"tags":["auth","sign-in","oauth","password"],"backgroundTag":"auth-method-mismatch","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"}