makeplane/plane · error · Error

Member not found

Error message

Member not found

What it means

Thrown by updateMemberRole in the project member store when getProjectMemberDetails(userId, projectId) returns falsy or has no id. This is a precondition check before the optimistic role update + REST call to updateProjectMember, ensuring the local store has a member record to revert to on failure.

Source

Thrown at apps/web/core/store/member/project/base-project-member.store.ts:351

  /**
   * @description Returns the role to use when updating a project member
   * @param projectId
   * @param userId
   * @param role
   */
  getProjectMemberRoleForUpdate = (_projectId: string, _userId: string, role: EUserProjectRoles): EUserProjectRoles =>
    role;

  /**
   * @description update the role of a member in a project
   * @param workspaceSlug
   * @param projectId
   * @param userId
   * @param data
   */
  updateMemberRole = async (workspaceSlug: string, projectId: string, userId: string, role: EUserProjectRoles) => {
    const memberDetails = this.getProjectMemberDetails(userId, projectId);
    if (!memberDetails || !memberDetails?.id) throw new Error("Member not found");
    // original data to revert back in case of error
    const isCurrentUser = this.rootStore.user.data?.id === userId;
    const membershipBeforeUpdate = { ...this.getProjectMembershipByUserId(userId, projectId) };
    const permissionBeforeUpdate = isCurrentUser
      ? this.rootStore.user.permission.getProjectRoleByWorkspaceSlugAndProjectId(workspaceSlug, projectId)
      : undefined;
    const updatedProjectRole = this.getProjectMemberRoleForUpdate(projectId, userId, role);
    try {
      runInAction(() => {
        set(this.projectMemberMap, [projectId, userId, "original_role"], role);
        set(this.projectMemberMap, [projectId, userId, "role"], updatedProjectRole);
        if (isCurrentUser) {
          set(
            this.rootStore.user.permission.workspaceProjectsPermissions,
            [workspaceSlug, projectId],
            updatedProjectRole
          );
        }

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Ensure fetchProjectMembers for the project has resolved before enabling the role-change action (gate the UI on member presence).
  2. Re-fetch the project member list and retry; the member may simply not be loaded yet.
  3. Confirm the userId is still a project member — if removed elsewhere, refresh state and remove the row.
  4. Guard the action with a getProjectMemberDetails check at the call site and show a loading state instead of invoking.

Example fix

// before: action invoked even when member not in store
updateMemberRole = async (workspaceSlug, projectId, userId, role) => {
  const memberDetails = this.getProjectMemberDetails(userId, projectId);
  if (!memberDetails || !memberDetails?.id) throw new Error("Member not found");
// after: caller-side guard prevents the call
const canChange = Boolean(this.getProjectMemberDetails(userId, projectId)?.id);
if (!canChange) return;
Defensive patterns

Strategy: validation

Validate before calling

const member = projectMemberStore.getProjectMemberDetails(userId, projectId);
if (!member?.id) {
  await projectMemberStore.fetchProjectMembers(workspaceSlug, projectId);
  return;
}

Type guard

const hasMemberId = (m: unknown): m is { id: string } =>
  typeof m === 'object' && m !== null && typeof (m as any).id === 'string';

Try / catch

try { await updateMemberRole(workspaceSlug, projectId, userId, role); }
catch (e) { showRoleUpdateError(); }

Prevention

When it happens

Trigger: Opening a project member's role dropdown and saving before the project member list for that project has been fetched/loaded into projectMemberMap; the userId passed in does not correspond to any member of that project (already removed, or never a member); the member record exists but its id field is unset due to a partial store hydration.

Common situations: Admin opens the members panel via a deep link before the member list request resolves; race after a member was just removed in another tab; stale userId from a closed panel; SSR/initial render firing the action before data is in.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/a77a53e41de96e6f. Report an issue: GitHub.