plandex-ai/plandex · warning

User does not have permission to delete project

Error message

User does not have permission to delete project

What it means

This 403 is returned by authorizeProjectDelete after authorizeProject succeeds but the user lacks shared.PermissionDeleteAnyProject. The project exists in the org, but deletion is restricted to users with that permission (owners/admins). It prevents non-privileged members from destroying shared projects.

Source

Thrown at app/server/handlers/auth_helpers.go:662

	}

	if !auth.HasPermission(shared.PermissionRenameAnyProject) {
		log.Println("User does not have permission to rename project")
		http.Error(w, "User does not have permission to rename project", http.StatusForbidden)
		return false
	}

	return true
}

func authorizeProjectDelete(w http.ResponseWriter, projectId string, auth *types.ServerAuth) bool {
	if !authorizeProject(w, projectId, auth) {
		return false
	}

	if !auth.HasPermission(shared.PermissionDeleteAnyProject) {
		log.Println("User does not have permission to delete project")
		http.Error(w, "User does not have permission to delete project", http.StatusForbidden)
		return false
	}

	return true
}

func authorizePlan(w http.ResponseWriter, planId string, auth *types.ServerAuth) *db.Plan {
	log.Println("authorizing plan")

	plan, err := db.ValidatePlanAccess(planId, auth.User.Id, auth.OrgId)

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

	if plan == nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Have an owner/admin (holder of PermissionDeleteAnyProject) perform the deletion
  2. Grant the user or service account the PermissionDeleteAnyProject permission if deletion is legitimately required
  3. Update automation to use a token with delete scope
  4. Hide delete actions in the client for users without the permission

Example fix

// before
await api.deleteProject(projectId);
// after
if (!auth.permissions.includes('delete_any_project')) {
  throw new Error('Deleting a project requires delete-any-project permission; contact an admin');
}
await api.deleteProject(projectId);
Defensive patterns

Strategy: type-guard

Validate before calling

function canDeleteProjects(auth) {
  return auth.user.role === 'owner' || auth.user.role === 'admin' ||
         auth.permissions.includes('delete_any_project');
}

Type guard

function hasPermission(auth, perm) {
  return Array.isArray(auth?.permissions) && auth.permissions.includes(perm);
}

Try / catch

try {
  await api.deleteProject(projectId);
} catch (e) {
  if (e.status === 403 && /permission to delete project/.test(e.body)) {
    notifyUser('Deletion requires delete-any-project permission; contact an admin');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A delete-project endpoint handler calls authorizeProjectDelete with a user whose auth context lacks PermissionDeleteAnyProject — e.g., a regular member or a scoped service token issuing DELETE for a project.

Common situations: A member attempts to delete a team project; automation using a restricted token tries cleanup deletes; role demotion removed delete rights but old scripts keep running.

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/8cb48ad77c2c8e6a. Report an issue: GitHub.