{"record":{"id":"49ea4352a4569018","repo":"toeverything/AFFiNE","slug":"member-not-found-in-space","errorCode":"member_not_found_in_space","errorMessage":"Member not found in Space ${spaceId}.","messagePattern":"Member not found in Space (.+?)\\.","errorType":"http","errorClass":"MemberNotFoundInSpace","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/workspaces/resolvers/member.ts","lineNumber":559,"sourceCode":"              userId,\n              WorkspaceMemberStatus.Accepted\n            );\n          }\n        }\n\n        this.event.emit('workspace.members.updated', {\n          workspaceId,\n        });\n\n        await this.workspaceService.sendReviewApprovedNotification(\n          role.id,\n          me.id\n        );\n        await this.policy.reconcileWorkspaceQuotaState(workspaceId);\n      }\n      return true;\n    } else {\n      throw new MemberNotFoundInSpace({ spaceId: workspaceId });\n    }\n  }\n\n  @Mutation(() => Boolean)\n  async grantMember(\n    @CurrentUser() user: CurrentUser,\n    @Args('workspaceId') workspaceId: string,\n    @Args('userId') userId: string,\n    @Args('permission', { type: () => WorkspaceRole }) newRole: WorkspaceRole\n  ) {\n    await this.ac\n      .user(user.id)\n      .workspace(workspaceId)\n      .assert(\n        newRole === WorkspaceRole.Owner\n          ? 'Workspace.TransferOwner'\n          : 'Workspace.Users.Manage'\n      );","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/workspaces/resolvers/member.ts#L541-L577","documentation":"Thrown by the invite-accept/approve mutation when models.workspaceUser.get(workspaceId, userId) returns no role record - the member row does not exist for that user/workspace pair. Reported as member_not_found_in_space (action_forbidden, HTTP 403).","triggerScenarios":"Calling accept/approve for a userId that has no workspaceUser row in the given workspace (never invited, already removed, or wrong id).","commonSituations":"Stale invite link after the membership was revoked; wrong userId passed (typo or cross-workspace id); the member was already removed by an admin.","solutions":["Verify the userId actually has a pending/UnderReview membership in that workspace before accepting.","Re-issue the invite to create a fresh membership row.","Check the workspaceId/userId pairing - membership is scoped per workspace."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const membership = await getWorkspaceUser(workspaceId, userId);\nif (!membership) throw new Error('No membership record; request a new invite');\n// only then accept/approve","typeGuard":"function hasMembership(row: unknown): row is { status: string } {\n  return !!row && typeof (row as any).status === 'string';\n}","tryCatchPattern":"try {\n  await acceptInvite(workspaceId);\n} catch (e) {\n  if (isGraphQLError(e, 'member_not_found_in_space')) showInvalidInviteNotice();\n  else throw e;\n}","preventionTips":["Confirm a pending/UnderReview membership exists before accepting.","Re-issue the invite if the row was removed.","Validate the workspaceId/userId pair - membership is per workspace."],"tags":["graphql","invite","workspace","state","validation"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}