theonedev/onedev · error · UnauthorizedException

Issue schedule permission required to set own estimated time

Error message

Issue schedule permission required to set own estimated time. Remove ownEstimatedTime if you want to create issue without setting own estimated time.

What it means

Thrown when the API caller sets ownEstimatedTime on issue creation but the authenticated user lacks the issue schedule permission for the target project. Even with an active subscription and time tracking enabled, SecurityUtils.canScheduleIssues(project) must return true. Returns HTTP 401 (UnauthorizedException) with a self-explanatory message.

Source

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

    @POST
    public Long createIssue(@NotNull @Valid IssueOpenData data) {
		var subject = SecurityUtils.getSubject();
    	var user = SecurityUtils.getUser(subject);
    	
    	Project project = projectService.load(data.getProjectId());
    	if (!SecurityUtils.canAccessProject(project))
			throw new UnauthorizedException();

		if (data.getIterationIds() != null && !data.getIterationIds().isEmpty() && !SecurityUtils.canScheduleIssues(project))
			throw new UnauthorizedException("No permission to schedule issue. Remove iterationIds if you want to create issue without scheduling it.");

		if (data.getOwnEstimatedTime() != null) {
 			if (!subscriptionService.isSubscriptionActive())			
				throw new NotAcceptableException("An active subscription is required for this feature");
			if (!project.isTimeTracking())
				throw new NotAcceptableException("Time tracking needs to be enabled for the project");
			if (!SecurityUtils.canScheduleIssues(project))
				throw new UnauthorizedException("Issue schedule permission required to set own estimated time. Remove ownEstimatedTime if you want to create issue without setting own estimated time.");
		}

		var issueSetting = settingService.getIssueSetting();
		
		Issue issue = new Issue();
		issue.setTitle(data.getTitle());
		issue.setDescription(data.getDescription());
		issue.setConfidential(data.isConfidential());
		issue.setProject(project);
		issue.setSubmitDate(new Date());
		issue.setSubmitter(user);
		issue.setState(issueSetting.getInitialStateSpec().getName());
		if (data.getOwnEstimatedTime() != null)
			issue.setOwnEstimatedTime(data.getOwnEstimatedTime());

		if (data.getIterationIds() != null) {
			for (Long iterationId : data.getIterationIds()) {
				Iteration iteration = iterationService.load(iterationId);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the user/role 'Schedule issues' permission in the project or parent permissions.
  2. Remove ownEstimatedTime from the request if estimates are not required.
  3. Perform the call as a user with schedule permission (e.g., an access token of an admin or project maintainer).

Example fix

// before (user lacks permission)
POST /api/issues {"title":"t","ownEstimatedTime":120}
// after: either drop the field
POST /api/issues {"title":"t"}
// or grant Schedule Issues permission to the role in Project -> Access Management
Defensive patterns

Strategy: validation

Validate before calling

const perms = await getMyProjectPermissions(projectPath);
if (body.ownEstimatedTime != null && !perms.includes('SCHEDULE_ISSUES'))
  throw new Error('Missing schedule issue permission; drop ownEstimatedTime or request access');

Type guard

function canSchedule(user, project) {
  return user?.projectPermissions?.[project.path]?.includes('SCHEDULE_ISSUES') ?? false;
}

Try / catch

try {
  await api.createIssue(body);
} catch (e) {
  if (e.status === 401 && /Issue schedule permission/.test(e.message))
    retryWithoutEstimates(body);
  else throw e;
}

Prevention

When it happens

Trigger: POST to /api/issues (createIssue) with ownEstimatedTime != null while the current user is not authorized to schedule issues in the project (missing schedule issue permission in project/role settings).

Common situations: Service accounts or regular users without the 'Schedule issues' permission attempting to automate issue creation with time estimates; permission grants changed or role downgraded.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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