{"record":{"id":"accfc56921fb1bf9","repo":"plandex-ai/plandex","slug":"only-the-plan-owner-can-rename-a-plan","errorCode":null,"errorMessage":"Only the plan owner can rename a plan","messagePattern":"Only the plan owner can rename a plan","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"app/server/handlers/plans_crud.go","lineNumber":187,"sourceCode":"\n\tlog.Println(\"planId: \", planId)\n\n\tplan := authorizePlan(w, planId, auth)\n\n\tif plan == nil {\n\t\treturn\n\t}\n\n\tvar requestBody shared.RenamePlanRequest\n\tif err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {\n\t\tlog.Printf(\"Error parsing request body: %v\\n\", err)\n\t\thttp.Error(w, \"Error parsing request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif plan.OwnerId != auth.User.Id {\n\t\tlog.Println(\"Only the plan owner can rename a plan\")\n\t\thttp.Error(w, \"Only the plan owner can rename a plan\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tif requestBody.Name == \"\" {\n\t\tlog.Println(\"Name cannot be empty\")\n\t\thttp.Error(w, \"Name cannot be empty\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\terr := db.RenamePlan(planId, requestBody.Name, nil)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error renaming plan: %v\\n\", err)\n\t\thttp.Error(w, \"Error renaming plan: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully renamed plan\")","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_crud.go#L169-L205","documentation":"RenamePlanHandler returns this 403 when the authenticated user is not the owner of the plan (plan.OwnerId != auth.User.Id). Renaming is restricted to the plan's original creator even if the user is a member of the org/project with general access. This is an authorization policy rejection, not a technical failure.","triggerScenarios":"Authenticated member (non-owner) issues POST rename on a plan owned by a teammate; plan ownership not transferred after the original owner left the org; API token belonging to a different user than the plan creator.","commonSituations":"Team member tries to rename a colleague's plan via CLI; offboarding didn't reassign plan ownership; a service account token is used for a plan created by a human user; shared project where all plans were created by one admin.","solutions":["Have the plan owner perform the rename, or log in as them","Transfer ownership of the plan to the intended user (update plans.owner_id, if a transfer flow exists)","Ask an admin to rename via the owner's account per policy","If the product should allow org admins to rename, file/change the handler to permit admins — but do not bypass client-side"],"exampleFix":"// before\ncurl -X POST .../plans/$ID/rename -H \"Authorization: Bearer $TEAMMATE_TOKEN\" -d '{\"name\":\"x\"}'\n// after\ncurl -X POST .../plans/$ID/rename -H \"Authorization: Bearer $OWNER_TOKEN\" -d '{\"name\":\"x\"}'","handlingStrategy":"validation","validationCode":"if plan.OwnerId != currentUser.Id { return errors.New(\"only the plan owner can rename this plan\") }","typeGuard":null,"tryCatchPattern":"resp, err := client.RenamePlan(planId, name)\nif apiErr, ok := asApiError(resp, err); ok && resp.StatusCode == 403 {\n\t// surface ownership requirement to the user or fall back to the owner\n}","preventionTips":["Check plan ownership client-side (plan.ownerId) before offering rename UI/actions","Run automation with a token belonging to the plan owner or transfer ownership first","Reassign plan ownership during offboarding workflows","Distinguish 403 (policy) from 400/500 in client error handling"],"tags":["authorization","forbidden","ownership","permissions"],"backgroundTag":"insufficient-permissions","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}