{"record":{"id":"24879a9b525b2e62","repo":"toeverything/AFFiNE","slug":"invalid-invitation","errorCode":"invalid_invitation","errorMessage":"Invalid invitation provided.","messagePattern":"Invalid invitation provided\\.","errorType":"http","errorClass":"InvalidInvitation","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/core/workspaces/resolvers/member.ts","lineNumber":704,"sourceCode":"\n  @Mutation(() => Boolean)\n  @Public()\n  async acceptInviteById(\n    @CurrentUser() user: CurrentUser | undefined,\n    @Args('inviteId') inviteId: string,\n    @Args('workspaceId', { deprecationReason: 'never used', nullable: true })\n    _workspaceId: string,\n    @Args('sendAcceptMail', {\n      nullable: true,\n      deprecationReason: 'never used',\n    })\n    _sendAcceptMail: boolean\n  ) {\n    const role = await this.models.workspaceUser.getById(inviteId);\n    // invitation by email\n    if (role) {\n      if (user && user.id !== role.userId) {\n        throw new InvalidInvitation();\n      }\n\n      await this.acceptInvitationByEmail(role);\n    } else {\n      // invitation by link\n      if (!user) {\n        throw new AuthenticationRequired();\n      }\n\n      const invitation = await this.cache.get<{\n        workspaceId: string;\n        inviterUserId: string;\n      }>(`workspace:inviteLinkId:${inviteId}`);\n\n      if (!invitation) {\n        throw new InvalidInvitation();\n      }\n","sourceCodeStart":686,"sourceCodeEnd":722,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/workspaces/resolvers/member.ts#L686-L722","documentation":"Thrown by `acceptInviteById` on the email-invitation branch when an invitation row exists for `inviteId`, the caller is signed in, but `user.id !== role.userId` — i.e. a different authenticated account is trying to accept an invitation emailed to someone else. Classified as `invalid_invitation` (invalid_input).","triggerScenarios":"Clicking an invite link while signed in as account B when the invite was emailed to account A; sharing an email-invite id with a colleague who is logged into their own account; a session that was switched mid-flow.","commonSituations":"User received the invite at work email but is signed in with a personal account; browser auto-filled a different account; testing invites by forwarding the link to another user who is already authenticated.","solutions":["Sign out and accept the invite in an incognito window, then sign in with the exact email the invite was sent to.","Have an admin re-send the invitation to the account the user is actually signed in with.","In the client, compare the invited email to the current session email before calling `acceptInviteById`.","If the invite is meant to be transferable, use a link invitation instead of an email invitation."],"exampleFix":"// before\nawait sdk.acceptInviteById({ inviteId });\n\n// after\nconst info = await sdk.getInviteInfo({ inviteId });\nif (currentUser && info.inviteeUserId && currentUser.id !== info.inviteeUserId) {\n  promptSignOutAndRedirect(inviteId);\n  return;\n}\nawait sdk.acceptInviteById({ inviteId });","handlingStrategy":"validation","validationCode":"// Compare current session to the invited user before accepting\nconst info = await sdk.getInviteInfo({ inviteId });\nif (currentUser && info.inviteeUserId && currentUser.id !== info.inviteeUserId) {\n  promptSignOut(inviteId);\n  return;\n}\nawait sdk.acceptInviteById({ inviteId });","typeGuard":"function inviteMatchesSession(currentUser, inviteInfo) {\n  return !currentUser || !inviteInfo.inviteeUserId || currentUser.id === inviteInfo.inviteeUserId;\n}","tryCatchPattern":"try {\n  await sdk.acceptInviteById({ inviteId });\n} catch (e) {\n  if (e.code === 'invalid_invitation') {\n    notify('Sign in with the email that received this invite, or request a new one.');\n  } else throw e;\n}","preventionTips":["Accept email invites in a session matching the invited email.","Compare session user id to the invitee before accepting.","Use link invites if the invite should be transferable between users."],"tags":["graphql","workspace","invitation","authentication","nestjs"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}