toeverything/AFFiNE · error · MemberNotFoundInSpace
member_not_found_in_space
member_not_found_in_space
Error message
Member not found in Space ${spaceId}. What it means
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).
Source
Thrown at packages/backend/server/src/core/workspaces/resolvers/member.ts:559
userId,
WorkspaceMemberStatus.Accepted
);
}
}
this.event.emit('workspace.members.updated', {
workspaceId,
});
await this.workspaceService.sendReviewApprovedNotification(
role.id,
me.id
);
await this.policy.reconcileWorkspaceQuotaState(workspaceId);
}
return true;
} else {
throw new MemberNotFoundInSpace({ spaceId: workspaceId });
}
}
@Mutation(() => Boolean)
async grantMember(
@CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string,
@Args('userId') userId: string,
@Args('permission', { type: () => WorkspaceRole }) newRole: WorkspaceRole
) {
await this.ac
.user(user.id)
.workspace(workspaceId)
.assert(
newRole === WorkspaceRole.Owner
? 'Workspace.TransferOwner'
: 'Workspace.Users.Manage'
);View on GitHub (pinned to 26c515e050)
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.
Defensive patterns
Strategy: validation
Validate before calling
const membership = await getWorkspaceUser(workspaceId, userId);
if (!membership) throw new Error('No membership record; request a new invite');
// only then accept/approve Type guard
function hasMembership(row: unknown): row is { status: string } {
return !!row && typeof (row as any).status === 'string';
} Try / catch
try {
await acceptInvite(workspaceId);
} catch (e) {
if (isGraphQLError(e, 'member_not_found_in_space')) showInvalidInviteNotice();
else throw e;
} Prevention
- 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.
When it happens
Trigger: Calling accept/approve for a userId that has no workspaceUser row in the given workspace (never invited, already removed, or wrong id).
Common situations: Stale invite link after the membership was revoked; wrong userId passed (typo or cross-workspace id); the member was already removed by an admin.
Related errors
- too_many_request
- already_in_space
- user_not_found
- expect_to_revoke_doc_user_roles
- expect_to_update_doc_user_role
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/49ea4352a4569018.
Report an issue: GitHub.