{"record":{"id":"2ffdb922a3a027d8","repo":"theonedev/onedev","slug":"issue-schedule-permission-required-to-set-own-esti-2ffdb9","errorCode":null,"errorMessage":"Issue schedule permission required to set own estimated time","messagePattern":"Issue schedule permission required to set own estimated time","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java","lineNumber":411,"sourceCode":"    \tif (!SecurityUtils.canModifyIssue(subject, issue))\n\t\t\tthrow new UnauthorizedException();\n\t\tissueChangeService.changeConfidential(user, issue, confidential);\n\t\treturn Response.ok().build();\n    }\n\n\t@Api(order=1275)\n\t@Path(\"/{issueId}/own-estimated-time\")\n\t@POST\n\tpublic Response setOwnEstimatedTime(@PathParam(\"issueId\") Long issueId, int minutes) {\n\t\tIssue issue = issueService.load(issueId);\n\t\tvar subject = SecurityUtils.getSubject();\n\t\tvar user = SecurityUtils.getUser(subject);\n\t\tif (!subscriptionService.isSubscriptionActive())\n\t\t\tthrow new NotAcceptableException(\"An active subscription is required for this feature\");\n\t\tif (!issue.getProject().isTimeTracking())\n\t\t\tthrow new NotAcceptableException(\"Time tracking needs to be enabled for the project\");\n\t\tif (!SecurityUtils.canScheduleIssues(issue.getProject()))\n\t\t\tthrow new UnauthorizedException(\"Issue schedule permission required to set own estimated time\");\n\t\tissueChangeService.changeOwnEstimatedTime(user, issue, minutes);\n\t\treturn Response.ok().build();\n\t}\n\t\n\t@Api(order=1300, description=\"Schedule issue into specified iterations with list of iteration id\")\n\t@Path(\"/{issueId}/iterations\")\n    @POST\n    public Response setIterations(@PathParam(\"issueId\") Long issueId, List<Long> iterationIds) {\n\t\tIssue issue = issueService.load(issueId);\n\t\tvar subject = SecurityUtils.getSubject();\n\t\tvar user = SecurityUtils.getUser(subject);\n    \tif (!SecurityUtils.canScheduleIssues(subject, issue.getProject()))\n\t\t\tthrow new UnauthorizedException(\"Issue schedule permission required to set iterations\");\n\t\t\n    \tCollection<Iteration> iterations = new HashSet<>();\n    \tfor (Long iterationId: iterationIds) {\n    \t\tIteration iteration = iterationService.load(iterationId);\n\t    \tif (!iteration.getProject().isSelfOrAncestorOf(issue.getProject()))","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java#L393-L429","documentation":"The own-estimated-time endpoint requires the authenticated user to have issue schedule permission in the issue's project. SecurityUtils.canScheduleIssues(project) returning false yields an UnauthorizedException (HTTP 401), thrown after subscription and time-tracking checks.","triggerScenarios":"POST to /api/issues/{issueId}/own-estimated-time by a user (or token) lacking the schedule issues permission in the issue's project.","commonSituations":"CI/service accounts with read/report access only; users whose role was stripped of schedule permission; using a personal access token of a restricted user in scripts.","solutions":["Grant the user's role the 'Schedule issues' permission for the project.","Call the endpoint with credentials of a user who can schedule issues.","Use the UI or a permitted account for estimate updates."],"exampleFix":"// before: 401 Issue schedule permission required to set own estimated time\n// after: Project -> Access Management -> role -> enable Schedule Issues, then retry","handlingStrategy":"validation","validationCode":"const perms = await getMyProjectPermissions(projectPath);\nif (!perms.includes('SCHEDULE_ISSUES'))\n  throw new Error('Cannot set own estimated time: schedule issue permission missing');","typeGuard":"function hasSchedulePermission(subject, project) {\n  return subject?.effectivePermissions?.[project.path]?.includes('SCHEDULE_ISSUES') ?? false;\n}","tryCatchPattern":"try {\n  await api.setOwnEstimatedTime(issueId, minutes);\n} catch (e) {\n  if (e.status === 401 && /Issue schedule permission/.test(e.message))\n    throw new Error('Grant Schedule Issues permission to the token owner');\n  throw e;\n}","preventionTips":["Provision automation tokens from accounts with the needed project role.","Test permission changes in a staging project first.","Log the effective user (SecurityUtils user) when calling admin-ish endpoints."],"tags":["rest-api","permissions","authorization"],"backgroundTag":"permission-denied","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}