toeverything/AFFiNE · error · NotFound

not_found

not_found

Error message

Invitation not found

What it means

Thrown by WorkspaceService invite-info lookup when inviteId is neither a cached link invitation ('workspace:inviteLinkId:<id>') nor an existing workspaceUser record — i.e. the invitation identifier does not exist anymore (or never did).

Solutions

  1. Ask the workspace owner to send a fresh invitation (link or email).
  2. Verify the inviteId matches the one embedded in the invite URL exactly.
  3. Self-hosted: confirm the cache (Redis) is running and was not flushed, since link invites live only in cache.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const info = await gql.request(GET_INVITE_INFO, { inviteId });
} catch (e) {
  if (getGraphqlErrorCode(e) === 'not_found') {
    renderExpiredInvitePage(inviteId);
  }
}

Prevention

When it happens

Trigger: Calling the invite info query with an expired/already-consumed link invite id, an invitation record that was deleted (member removed), or a fabricated id.

Common situations: User opens an old invite page whose link invite expired in cache; the invited member was removed so the workspaceUser row is gone; self-hosted Redis flush wiped pending link invites.

Understand the failure class

Background: NOT_FOUND error code: why tRPC, Harbor, Nacos and other libraries return 404 "not found" errors for resources that may still exist — this error's family across 11 libraries.

Related errors


AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18). Data as JSON: /api/errors/d1a4aba2326a2cf5. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/workspaces/service.ts:124

    return storageUserIds;
  }

  async getInviteInfo(inviteId: string): Promise<InviteInfo> {
    // invite link
    const invite = await this.cache.get<InviteInfo>(
      `workspace:inviteLinkId:${inviteId}`
    );
    if (typeof invite?.workspaceId === 'string') {
      return {
        ...invite,
        isLink: true,
      };
    }

    const workspaceUser = await this.models.workspaceUser.getById(inviteId);

    if (!workspaceUser) {
      throw new NotFound('Invitation not found');
    }

    return {
      isLink: false,
      workspaceId: workspaceUser.workspaceId,
      inviteeUserId: workspaceUser.userId,
      inviterUserId: workspaceUser.inviterId,
    };
  }

  async getWorkspaceInfo(workspaceId: string) {
    const workspaceContent = await this.doc.getWorkspaceContent(workspaceId);

    let avatar = DEFAULT_WORKSPACE_AVATAR;
    if (workspaceContent?.avatarKey) {
      try {
        const owner = await this.models.workspaceUser.getOwner(workspaceId);
        avatar = (

View on GitHub (pinned to 2af30773ae)