plandex-ai/plandex · warning

User does not have permission to delete plan

Error message

User does not have permission to delete plan

What it means

This 403 is returned by authorizePlanDelete when the plan is accessible but the requester is neither the plan owner nor a holder of shared.PermissionDeleteAnyPlan. Deleting a plan is reserved for its owner or users with the delete-any-plan admin permission.

Source

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

	if plan.OwnerId != auth.User.Id && !auth.HasPermission(shared.PermissionUpdateAnyPlan) {
		log.Println("User does not have permission to update plan")
		http.Error(w, "User does not have permission to update plan", http.StatusForbidden)
		return nil
	}

	return plan
}

func authorizePlanDelete(w http.ResponseWriter, planId string, auth *types.ServerAuth) *db.Plan {
	plan := authorizePlan(w, planId, auth)

	if plan == nil {
		return nil
	}

	if plan.OwnerId != auth.User.Id && !auth.HasPermission(shared.PermissionDeleteAnyPlan) {
		log.Println("User does not have permission to delete plan")
		http.Error(w, "User does not have permission to delete plan", http.StatusForbidden)
		return nil
	}

	return plan
}

func authorizePlanRename(w http.ResponseWriter, planId string, auth *types.ServerAuth) *db.Plan {
	plan := authorizePlan(w, planId, auth)

	if plan == nil {
		return nil
	}

	if plan.OwnerId != auth.User.Id && !auth.HasPermission(shared.PermissionRenameAnyPlan) {
		log.Println("User does not have permission to rename plan")
		http.Error(w, "User does not have permission to rename plan", http.StatusForbidden)
		return nil
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Have the plan owner or an admin with PermissionDeleteAnyPlan delete the plan
  2. Grant the user/service account PermissionDeleteAnyPlan if policy allows
  3. Reassign ownership before deletion if the owner is offboarded
  4. Gate delete actions in the client on ownership or the delete permission

Example fix

// before
await api.deletePlan(planId);
// after
if (plan.ownerId !== auth.userId && !auth.permissions.includes('delete_any_plan')) {
  throw new Error('Only the plan owner or an admin can delete this plan');
}
await api.deletePlan(planId);
Defensive patterns

Strategy: type-guard

Validate before calling

function canDeletePlan(plan, auth) {
  return plan.ownerId === auth.userId || auth.permissions.includes('delete_any_plan');
}

Type guard

function isPlanOwner(plan, auth) {
  return typeof plan?.ownerId === 'string' && plan.ownerId === auth?.userId;
}

Try / catch

try {
  await api.deletePlan(planId);
} catch (e) {
  if (e.status === 403 && /permission to delete plan/.test(e.body)) {
    notifyUser('Only the plan owner or an admin can delete this plan');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: DeletePlanHandler invoked by a non-owner member lacking PermissionDeleteAnyPlan, issuing DELETE for a plan owned by someone else.

Common situations: A team member tries to remove a plan created by a former employee; cleanup scripts running under a non-privileged token; UI still shows delete buttons after role changes.

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/44f1c87ecf810a3d. Report an issue: GitHub.