theonedev/onedev · error · UnauthorizedException

Issue schedule permission required to set iterations

Error message

Issue schedule permission required to set iterations

What it means

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.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java:424

		if (!subscriptionService.isSubscriptionActive())
			throw new NotAcceptableException("An active subscription is required for this feature");
		if (!issue.getProject().isTimeTracking())
			throw new NotAcceptableException("Time tracking needs to be enabled for the project");
		if (!SecurityUtils.canScheduleIssues(issue.getProject()))
			throw new UnauthorizedException("Issue schedule permission required to set own estimated time");
		issueChangeService.changeOwnEstimatedTime(user, issue, minutes);
		return Response.ok().build();
	}
	
	@Api(order=1300, description="Schedule issue into specified iterations with list of iteration id")
	@Path("/{issueId}/iterations")
    @POST
    public Response setIterations(@PathParam("issueId") Long issueId, List<Long> iterationIds) {
		Issue issue = issueService.load(issueId);
		var subject = SecurityUtils.getSubject();
		var user = SecurityUtils.getUser(subject);
    	if (!SecurityUtils.canScheduleIssues(subject, issue.getProject()))
			throw new UnauthorizedException("Issue schedule permission required to set iterations");
		
    	Collection<Iteration> iterations = new HashSet<>();
    	for (Long iterationId: iterationIds) {
    		Iteration iteration = iterationService.load(iterationId);
	    	if (!iteration.getProject().isSelfOrAncestorOf(issue.getProject()))
	    		throw new NotAcceptableException("Iteration is not defined in project hierarchy of the issue");
	    	iterations.add(iteration);
    	}
    	
    	issueChangeService.changeIterations(user, issue, iterations);
    	
		return Response.ok().build();
    }
	
	@Api(order=1400)
	@Path("/{issueId}/fields")
    @POST
    public Response setFields(@PathParam("issueId") Long issueId, @NotNull @Api(exampleProvider = "getFieldsExample") Map<String, Serializable> fields) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the caller's role the schedule issues permission in the project.
  2. Retry with an account/token that has schedule permission.
  3. Manage iterations through the UI as a permitted user.

Example fix

// before: 401 Issue schedule permission required to set iterations
// after: assign Schedule Issues permission to the role, then POST iterations again
Defensive patterns

Strategy: validation

Validate before calling

const perms = await getMyProjectPermissions(projectPath);
if (!perms.includes('SCHEDULE_ISSUES'))
  throw new Error('Cannot set iterations: schedule issue permission missing for ' + projectPath);

Type guard

function canSetIterations(subject, project) {
  return subject?.effectivePermissions?.[project.path]?.includes('SCHEDULE_ISSUES') ?? false;
}

Try / catch

try {
  await api.setIterations(issueId, iterationIds);
} catch (e) {
  if (e.status === 401 && /schedule permission required to set iterations/.test(e.message))
    log.warn('Need Schedule Issues permission');
  else throw e;
}

Prevention

When it happens

Trigger: POST /api/issues/{issueId}/iterations with a list of iteration ids while the caller lacks schedule issues permission in the issue's project.

Common situations: Automation moving issues between iterations with an under-privileged token; users with only edit-issue but not schedule permission.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/77a932faa11454de. Report an issue: GitHub.