{"record":{"id":"77a932faa11454de","repo":"theonedev/onedev","slug":"issue-schedule-permission-required-to-set-iteratio-77a932","errorCode":null,"errorMessage":"Issue schedule permission required to set iterations","messagePattern":"Issue schedule permission required to set iterations","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java","lineNumber":424,"sourceCode":"\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()))\n\t    \t\tthrow new NotAcceptableException(\"Iteration is not defined in project hierarchy of the issue\");\n\t    \titerations.add(iteration);\n    \t}\n    \t\n    \tissueChangeService.changeIterations(user, issue, iterations);\n    \t\n\t\treturn Response.ok().build();\n    }\n\t\n\t@Api(order=1400)\n\t@Path(\"/{issueId}/fields\")\n    @POST\n    public Response setFields(@PathParam(\"issueId\") Long issueId, @NotNull @Api(exampleProvider = \"getFieldsExample\") Map<String, Serializable> fields) {","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java#L406-L442","documentation":"The setIterations endpoint (POST /api/issues/{issueId}/iterations) requires issue schedule permission in the issue's project. If SecurityUtils.canScheduleIssues(subject, project) fails, UnauthorizedException (HTTP 401) is thrown before any iteration validation.","triggerScenarios":"POST /api/issues/{issueId}/iterations with a list of iteration ids while the caller lacks schedule issues permission in the issue's project.","commonSituations":"Automation moving issues between iterations with an under-privileged token; users with only edit-issue but not schedule permission.","solutions":["Grant the caller's role the schedule issues permission in the project.","Retry with an account/token that has schedule permission.","Manage iterations through the UI as a permitted user."],"exampleFix":"// before: 401 Issue schedule permission required to set iterations\n// after: assign Schedule Issues permission to the role, then POST iterations again","handlingStrategy":"validation","validationCode":"const perms = await getMyProjectPermissions(projectPath);\nif (!perms.includes('SCHEDULE_ISSUES'))\n  throw new Error('Cannot set iterations: schedule issue permission missing for ' + projectPath);","typeGuard":"function canSetIterations(subject, project) {\n  return subject?.effectivePermissions?.[project.path]?.includes('SCHEDULE_ISSUES') ?? false;\n}","tryCatchPattern":"try {\n  await api.setIterations(issueId, iterationIds);\n} catch (e) {\n  if (e.status === 401 && /schedule permission required to set iterations/.test(e.message))\n    log.warn('Need Schedule Issues permission');\n  else throw e;\n}","preventionTips":["Verify role permissions for the account used by schedulers/bots.","Separate read tokens from write tokens and grant write tokens the minimum needed scopes.","Document required permissions for each integration."],"tags":["rest-api","permissions","iterations","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"}