{"record":{"id":"263dfbfcf62757d1","repo":"plandex-ai/plandex","slug":"user-does-not-have-permission-to-archive-plan","errorCode":null,"errorMessage":"User does not have permission to archive plan","messagePattern":"User does not have permission to archive plan","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"app/server/handlers/auth_helpers.go","lineNumber":746,"sourceCode":"\tif plan.OwnerId != auth.User.Id && !auth.HasPermission(shared.PermissionRenameAnyPlan) {\n\t\tlog.Println(\"User does not have permission to rename plan\")\n\t\thttp.Error(w, \"User does not have permission to rename plan\", http.StatusForbidden)\n\t\treturn nil\n\t}\n\n\treturn plan\n}\n\nfunc authorizePlanArchive(w http.ResponseWriter, planId string, auth *types.ServerAuth) *db.Plan {\n\tplan := authorizePlan(w, planId, auth)\n\n\tif plan == nil {\n\t\treturn nil\n\t}\n\n\tif plan.OwnerId != auth.User.Id && !auth.HasPermission(shared.PermissionArchiveAnyPlan) {\n\t\tlog.Println(\"User does not have permission to archive plan\")\n\t\thttp.Error(w, \"User does not have permission to archive plan\", http.StatusForbidden)\n\t\treturn nil\n\t}\n\n\treturn plan\n}\n","sourceCodeStart":728,"sourceCodeEnd":752,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/auth_helpers.go#L728-L752","documentation":"This 403 is returned by authorizePlanArchive when the plan is accessible but the requester is neither the plan owner nor holds shared.PermissionArchiveAnyPlan. Archiving (and unarchiving, via ArchivePlanHandler/UnarchivePlanHandler) is limited to the owner or users with the archive-any-plan admin permission.","triggerScenarios":"ArchivePlanHandler or UnarchivePlanHandler called by a non-owner member lacking PermissionArchiveAnyPlan attempting to change the plan's archived state.","commonSituations":"A member tries to archive a completed team plan owned by someone else; batch-archival automation runs with insufficient token scope; stale UI offering archive toggles after a role change.","solutions":["Have the plan owner or an admin with PermissionArchiveAnyPlan archive/unarchive the plan","Grant PermissionArchiveAnyPlan to the automation account if scheduled archiving is required","Hide archive toggles for non-owners lacking the permission","Transfer ownership if the current owner is unavailable"],"exampleFix":"// before\nawait api.archivePlan(planId);\n// after\nif (plan.ownerId !== auth.userId && !auth.permissions.includes('archive_any_plan')) {\n  throw new Error('Only the plan owner or an admin can archive this plan');\n}\nawait api.archivePlan(planId);","handlingStrategy":"type-guard","validationCode":"function canArchivePlan(plan, auth) {\n  return plan.ownerId === auth.userId || auth.permissions.includes('archive_any_plan');\n}","typeGuard":"function isPlanOwner(plan, auth) {\n  return typeof plan?.ownerId === 'string' && plan.ownerId === auth?.userId;\n}","tryCatchPattern":"try {\n  return await api.archivePlan(planId);\n} catch (e) {\n  if (e.status === 403 && /permission to archive plan/.test(e.body)) {\n    notifyUser('Only the plan owner or an admin can archive this plan');\n    return null;\n  }\n  throw e;\n}","preventionTips":["Gate archive/unarchive controls on ownership or archive-any-plan permission","Ensure automation tokens include archive scope for batch jobs","Re-fetch plan state after archive operations to stay consistent","Review permissions when ownership changes hands"],"tags":["http-403","authorization","permissions","ownership"],"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"}