{"record":{"id":"24de72fbbc2bfdb7","repo":"toeverything/AFFiNE","slug":"same-email-provided","errorCode":"same_email_provided","errorMessage":"You are trying to update your account email to the same as the old one.","messagePattern":"You are trying to update your account email to the same as the old one\\.","errorType":"exception","errorClass":"SameEmailProvided","httpStatus":400,"severity":"warning","filePath":"packages/backend/server/src/core/auth/resolver.ts","lineNumber":278,"sourceCode":"    const valid = await this.models.verificationToken.verify(\n      TokenType.ChangeEmail,\n      token,\n      {\n        credential: user.id,\n      }\n    );\n\n    if (!valid) {\n      throw new InvalidEmailToken();\n    }\n\n    const hasRegistered = await this.models.user.getUserByEmail(email);\n\n    if (hasRegistered) {\n      if (hasRegistered.id !== user.id) {\n        throw new EmailAlreadyUsed();\n      } else {\n        throw new SameEmailProvided();\n      }\n    }\n\n    const { token: verifyEmailToken, expiresAt } =\n      await this.models.verificationToken.createWithExpiresAt(\n        TokenType.VerifyEmail,\n        user.id\n      );\n\n    const url = this.url.safeLink(callbackUrl, {\n      token: verifyEmailToken,\n      email,\n    });\n    return await this.auth.sendVerifyChangeEmail(\n      email,\n      url,\n      this.mailMetadata(context, expiresAt)\n    );","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/core/auth/resolver.ts#L260-L296","documentation":"Thrown by sendVerifyChangeEmail when getUserByEmail(email) resolves to the current user's own account (hasRegistered.id === user.id). The flow refuses to run a no-op email change to the address the user already owns.","triggerScenarios":"Calling sendVerifyChangeEmail with an email identical to the signed-in user's current email.","commonSituations":"User retypes their existing address out of habit; form pre-filled with the current email and submitted unchanged; copy/paste of the wrong row from a password manager.","solutions":["Compare the entered email against currentUser.email client-side and block submission when equal","Show the current email next to the input so the change target is obvious","If hit in tests, update fixtures to use a genuinely different address"],"exampleFix":"// before\nawait client.request(sendVerifyChangeEmailMutation, { token, email, callbackUrl });\n\n// after\nif (email === me.email) {\n  setNotice('This is already your email address');\n  return;\n}\nawait client.request(sendVerifyChangeEmailMutation, { token, email, callbackUrl });","handlingStrategy":"validation","validationCode":"const normalized = email.trim().toLowerCase();\nif (normalized === me.email) {\n  setNotice('This is already your email address');\n} else {\n  await client.request(sendVerifyChangeEmailMutation, { token, email: normalized, callbackUrl });\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compare trimmed/lowercased emails against the current one client-side","Pre-fill nothing in the new-email field to avoid unchanged resubmission","Use distinct fixture emails in tests"],"tags":["auth","email","input-validation","graphql"],"backgroundTag":"duplicate-email-update","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"}