plandex-ai/plandex · warning

User does not have permission to remove user with role: {org

Error message

User does not have permission to remove user with role: {orgUser.OrgRoleId}

What it means

The authenticated caller lacks the composite permission "remove-user|<targetOrgRoleId>", so DeleteOrgUserHandler refuses with HTTP 403. The permission is dynamically built by joining PermissionRemoveUser with the target user's OrgRoleId, meaning callers need a matching grant per target role (e.g. separate grants for removing members vs admins vs owners).

Source

Thrown at app/server/handlers/users.go:144

	vars := mux.Vars(r)
	userId := vars["userId"]

	log.Println("userId: ", userId)

	orgUser, err := db.GetOrgUser(userId, auth.OrgId)

	if err != nil {
		log.Printf("Error getting org user: %v\n", err)
		http.Error(w, "Error getting org user: "+err.Error(), http.StatusInternalServerError)
		return
	}

	// ensure current user can remove target user
	removePermission := shared.Permission(strings.Join([]string{string(shared.PermissionRemoveUser), orgUser.OrgRoleId}, "|"))

	if !auth.HasPermission(removePermission) {
		log.Printf("User does not have permission to remove user with role: %v\n", orgUser.OrgRoleId)
		http.Error(w, "User does not have permission to remove user with role: "+orgUser.OrgRoleId, http.StatusForbidden)
		return
	}

	// verify user is org member
	isMember, err := db.ValidateOrgMembership(userId, auth.OrgId)

	if err != nil {
		log.Printf("Error validating org membership: %v\n", err)
		http.Error(w, "Error validating org membership: "+err.Error(), http.StatusInternalServerError)
		return
	}

	if !isMember {
		log.Printf("User %s is not a member of org %s\n", userId, auth.OrgId)
		http.Error(w, "User "+userId+" is not a member of org "+auth.OrgId, http.StatusForbidden)
		return
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Grant the caller's role the permission string remove-user|<orgUser.OrgRoleId> (exact pipe-joined form) in role config
  2. Check which role the target user has (org_users.org_role_id) and confirm your permission covers that specific role
  3. Re-authenticate to refresh permissions if role grants were changed recently
  4. Use a role with sufficient privileges (e.g. org owner) to perform the removal
Defensive patterns

Strategy: validation

Validate before calling

required := "remove-user|" + targetOrgRoleId
hasIt := slices.Contains(callerPermissions, required)
if !hasIt {
    return fmt.Errorf("missing permission %s", required)
}

Type guard

func canRemoveUser(perms []shared.Permission, targetRoleId string) bool {
    p := shared.Permission("remove-user|" + targetRoleId)
    return slices.Contains(perms, p)
}

Try / catch

if !auth.HasPermission(removePermission) {
    http.Error(w, "forbidden: missing "+string(removePermission), http.StatusForbidden)
    return
}
// client side:
// if resp.StatusCode == http.StatusForbidden { stop; surface 'insufficient permissions' }

Prevention

When it happens

Trigger: Caller's role permission set does not include remove-user|<role> for the specific OrgRoleId of the target user — e.g. an admin tries to delete another admin or an owner, or a member tries to delete anyone.

Common situations: Role config updated but the caller's cached JWT still has old permissions; only owner-level removal was granted but target is an admin; reusing an integration token with a read-only role; per-role permission scheme misunderstood by API consumers.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/e6bb70c26da3de91. Report an issue: GitHub.