{"record":{"id":"3d9b361d779b1704","repo":"toeverything/AFFiNE","slug":"user-not-found-3d9b36","errorCode":"user_not_found","errorMessage":"User not found.","messagePattern":"User not found\\.","errorType":"error_code","errorClass":"UserNotFound","httpStatus":404,"severity":"error","filePath":"packages/backend/server/src/models/user.ts","lineNumber":256,"sourceCode":"\n  /**\n   * Mark a existing user or create a new one as registered and email verified.\n   *\n   * When user created by others invitation, we will leave it as unregistered.\n   */\n  async fulfill(email: string, data: Omit<UpdateUserInput, 'email'> = {}) {\n    const user = await this.getUserByEmail(email, { withDisabled: true });\n\n    if (!user) {\n      return this.create({\n        email,\n        registered: true,\n        emailVerifiedAt: new Date(),\n        ...data,\n      });\n    } else {\n      if (user.disabled) {\n        throw new UserNotFound();\n      }\n\n      if (user.registered) {\n        delete data.registered;\n      } else {\n        data.registered = true;\n      }\n\n      if (user.emailVerifiedAt) {\n        delete data.emailVerifiedAt;\n      } else {\n        data.emailVerifiedAt = new Date();\n      }\n\n      if (Object.keys(data).length) {\n        return await this.update(user.id, data);\n      }\n    }","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/models/user.ts#L238-L274","documentation":"Thrown by UserModel.fulfill (user.ts:256) when the user matching the email exists but is disabled. fulfill is used to register/verify a user during invitation acceptance or email verification; a disabled user cannot be fulfilled. UserFriendlyError, code user_not_found, type resource_not_found, HTTP 404.","triggerScenarios":"A disabled user clicks an invitation or email-verification link; an OAuth callback runs for a disabled account; fulfill() is invoked on an email whose only record is disabled.","commonSituations":"Admin disabled the user between sending the invite and the user accepting; a banned user attempts to verify; an offboarding pipeline disabled the account mid-flow.","solutions":["Have an admin re-enable the account, then retry the link.","If the disable was intentional, reject the flow in the UI rather than retrying.","Avoid sending invitations to disabled users."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { UserNotFound } from '../base/error/errors.gen';\n\ntry {\n  await models.user.fulfill(email, data);\n} catch (e) {\n  if (e instanceof UserNotFound) {\n    // account is disabled; surface 'contact admin to re-enable'\n  } else throw e;\n}","preventionTips":["Don't send invitation/verification links to disabled users.","If an account is disabled mid-flow, fail fast rather than letting the user click through.","Surface a clear 'account disabled' message instead of a generic 404."],"tags":["auth","invitation","disabled-account"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}