theonedev/onedev · error · NotAcceptableException

Assignee should have code write permission:

Error message

Assignee should have code write permission: 

What it means

During PR creation, each id in assigneeIds is checked with SecurityUtils.canWriteCode on the project; if an assignee lacks code-write, a NotAcceptableException naming the assignee is thrown. OneDev requires assignees to be able to modify code since assignments imply work on the branch/code.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/PullRequestResource.java:309

				if (!SecurityUtils.canReadCode(request.getProject()))
					throw new NotAcceptableException("Reviewer should have code read permission: " + reviewer.getName());

				if (request.getReview(reviewer) == null) {
					PullRequestReview review = new PullRequestReview();
					review.setRequest(request);
					review.setUser(reviewer);
					request.getReviews().add(review);
				}
			}
		}

		if (data.getAssigneeIds() != null && !data.getAssigneeIds().isEmpty()) {
			for (Long assigneeId : data.getAssigneeIds()) {
				PullRequestAssignment assignment = new PullRequestAssignment();
				assignment.setRequest(request);
				var assignee = userService.load(assigneeId);
				if (!SecurityUtils.canWriteCode(request.getProject()))
					throw new NotAcceptableException("Assignee should have code write permission: " + assignee.getName());
				assignment.setUser(assignee);
				request.getAssignments().add(assignment);
			}
		}

		pullRequestService.open(request);

		return Response.ok(request.getId()).build();
    }
	
	@Api(order=1300)
	@Path("/{requestId}/title")
    @POST
    public Response setTitle(@PathParam("requestId") Long requestId, @NotEmpty String title) {
		PullRequest request = pullRequestService.load(requestId);
		var subject = SecurityUtils.getSubject();
		var user = SecurityUtils.getUser(subject);
    	if (!SecurityUtils.canModifyPullRequest(subject, request))

View on GitHub (pinned to d44925c47c)

Solutions

  1. Remove non-writer users from assigneeIds.
  2. Grant the intended assignee a role with code-write on the project.
  3. Assign users who can push branches in the project.
  4. Create PR without assignees and assign later via the UI once permissions are fixed.

Example fix

// before
{"assigneeIds":[8]}   // user 8 has only code-read
// after: grant user 8 code-write on the project, or
{"assigneeIds":[]}
Defensive patterns

Strategy: validation

Validate before calling

const canWrite = await fetch(`/~api/projects/${projectId}/permissions`)
// pass only assignees known to have write/code-write role on the project
const eligibleIds = assigneeIds.filter(id => writersByProject[projectId]?.includes(id))

Try / catch

try {
  await api.post('/pull-requests', {...data, assigneeIds})
} catch (e) {
  if (e.message?.startsWith('Assignee should have code write permission')) {
    // drop the named assignee and retry, or report to user
  } else throw e
}

Prevention

When it happens

Trigger: POST /~api/pull-requests with assigneeIds containing read-only users or guests; assigning project outsiders; service accounts with read-only tokens as assignees.

Common situations: Default assignee templates including users downgraded to read access; assigning managers/QA who never had write permission; integrations that blindly copy assignees from issues.

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/d1027feb97b0c144. Report an issue: GitHub.