plandex-ai/plandex · warning

User does not have permission to update plan

Error message

User does not have permission to update plan

What it means

authorizePlanExecUpdate checks that the authenticated user owns the plan (plan.OwnerId == auth.User.Id) or holds the shared.PermissionUpdateAnyPlan permission. If neither holds, it writes a 403 with 'User does not have permission to update plan' and returns nil (causing callers TellPlanHandler/BuildPlanHandler to abort). It is an authorization failure, not an authentication one.

Source

Thrown at app/server/handlers/plans_exec.go:627

		log.Printf("Error marshalling response: %v\n", err)
		http.Error(w, "Error marshalling response", http.StatusInternalServerError)
		return
	}

	w.Write(bytes)

	// log.Println("Successfully processed request for GetBuildStatusHandler")
}

func authorizePlanExecUpdate(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.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
}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Verify you are operating on a plan your user owns, or log in as the owner.
  2. Grant the user the PermissionUpdateAnyPlan permission if cross-user plan updates are intended.
  3. Check the auth token/key actually maps to the expected user (auth.User.Id) rather than a stale session.
  4. Confirm the planId in the request refers to the intended plan.

Example fix

// before
POST /plans/{someoneElsesPlanId}/tell  // 403
// after
grant := auth.HasPermission(shared.PermissionUpdateAnyPlan) // ask admin to enable, or use own plan
POST /plans/{yourPlanId}/tell
Defensive patterns

Strategy: validation

Validate before calling

// client-side pre-check: only call tell/build on plans you own or have rights to
if plan.OwnerId != currentUser.Id && !currentUser.Permissions.Contains("update_any_plan") {
    return errors.New("skipping: no permission to update this plan")
}

Type guard

func canUpdatePlan(p *shared.Plan, u *auth.User, has func(string) bool) bool {
    return p != nil && (p.OwnerId == u.Id || has(shared.PermissionUpdateAnyPlan))
}

Try / catch

resp, err := tellPlan(planId, msg)
if err != nil {
    var httpErr *HTTPError
    if errors.As(err, &httpErr) && httpErr.StatusCode == http.StatusForbidden {
        return fmt.Errorf("plan %s is owned by another user; request PermissionUpdateAnyPlan or use your own plan", planId)
    }
    return err
}

Prevention

When it happens

Trigger: TellPlanHandler or BuildPlanHandler is called by an authenticated user whose Id differs from plan.OwnerId and who lacks PermissionUpdateAnyPlan, at plans_exec.go:627.

Common situations: Team members trying to tell/build a colleague's plan without the 'update any plan' permission granted; API keys scoped to a different user; switching accounts while reusing a client with cached plan IDs.

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