toeverything/AFFiNE · error · UserNotFound

user_not_found

user_not_found

Error message

User not found.

What it means

Thrown by the getInviteInfo query when no invitee can be resolved: inviteeUserId from the invite is empty AND no current user is supplied, or the resolved inviteeId does not map to a workspace user record (models.user.getWorkspaceUser returns null). Reported as user_not_found (resource_not_found, HTTP 404).

Source

Thrown at packages/backend/server/src/core/workspaces/resolvers/member.ts:620

    return true;
  }

  @Throttle('strict')
  @Public()
  @Query(() => InvitationType, {
    description: 'get workspace invitation info',
  })
  async getInviteInfo(
    @CurrentUser() user: UserType | undefined,
    @Args('inviteId') inviteId: string
  ): Promise<InvitationType> {
    const { workspaceId, inviteeUserId, isLink } =
      await this.workspaceService.getInviteInfo(inviteId);
    const workspace = await this.workspaceService.getWorkspaceInfo(workspaceId);
    const owner = await this.models.workspaceUser.getOwner(workspaceId);

    const inviteeId = inviteeUserId || user?.id;
    if (!inviteeId) throw new UserNotFound();
    const invitee = await this.models.user.getWorkspaceUser(inviteeId);
    if (!invitee) throw new UserNotFound();

    let status: WorkspaceMemberStatus | undefined;
    if (isLink) {
      const invitation = await this.models.workspaceUser.get(
        workspaceId,
        inviteeId
      );
      status = invitation?.status;
    } else {
      const invitation = await this.models.workspaceUser.getById(inviteId);
      status = invitation?.status;
    }

    return { workspace, user: owner, invitee, status };
  }

View on GitHub (pinned to 26c515e050)

Solutions

  1. Ensure the caller is authenticated when the invite has no specific inviteeUserId (link invites).
  2. Validate the inviteId still maps to a live invite via the workspace service before calling getInviteInfo.
  3. Handle user_not_found in the UI by prompting sign-in or showing an 'invite no longer valid' state.
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure a session exists before fetching link-invite info
if (!currentUser && !inviteIdHasInvitee(inviteId)) {
  redirectToSignIn();
  return;
}

Try / catch

try {
  await getInviteInfo(inviteId);
} catch (e) {
  if (isGraphQLError(e, 'user_not_found')) showInviteInvalidNotice();
  else throw e;
}

Prevention

When it happens

Trigger: Calling getInviteInfo(inviteId) where the invite has no bound invitee and the request is anonymous, or the invitee id no longer corresponds to a user.

Common situations: Anonymous visitor opens an invite whose invitee record was deleted; the invite link is malformed/stale so inviteeUserId is empty and there is no session; the user account was hard-deleted after the invite was created.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/1dc2ed01df6cbb12. Report an issue: GitHub.