theonedev/onedev · error · NotAcceptableException

Reviewer needs to have read code permission to the project

Error message

Reviewer needs to have read code permission to the project

What it means

OneDev throws this NotAcceptableException (HTTP 400) from the REST endpoint POST /pull-requests/{requestId}/reviewers/{userId} when the caller tries to add a reviewer who lacks read-code permission on the pull request's target project. A reviewer must be able to see the code to review it, so the API refuses users outside the project's reader ACL. It is a validation of the target user's permissions, not the caller's.

Source

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

		return Response.ok().build();
    }

	@Api(order=1410)
	@Path("/{requestId}/reviewers/{userId}")
	@POST
	public Response addReviewer(@PathParam("requestId") Long requestId, @PathParam("userId") Long userId) {		
		var request = pullRequestService.load(requestId);
		var user = userService.load(userId);

		var currentUser = SecurityUtils.getUser();
		if (!SecurityUtils.canModifyPullRequest(currentUser.asSubject(), request)) 
			throw new UnauthorizedException();

		if (user.equals(request.getSubmitter()))
			throw new NotAcceptableException("Pull request submitter cannot be reviewer");

		if (!SecurityUtils.canReadCode(user.asSubject(), request.getProject()))
			throw new NotAcceptableException("Reviewer needs to have read code permission to the project");
			
		var review = request.getReview(user);
		if (review != null) {
			if (review.getStatus() == EXCLUDED) {
				review.setStatus(PENDING);
				pullRequestReviewService.createOrUpdate(currentUser, review);
			}
		} else {
			review = new PullRequestReview();
			review.setRequest(request);
			review.setUser(user);
			review.setStatus(PENDING);

			pullRequestReviewService.createOrUpdate(currentUser, review);	
		}

		return Response.ok().build();
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the reviewer at least 'Read Code' (Reader) permission on the target project, then retry the call.
  2. Pick a different userId that already has read access to the project.
  3. If project roles are the issue, add the user to a group with project read access and verify via the project's access configuration.

Example fix

// before: add arbitrary user as reviewer
POST /~api/pull-requests/42/reviewers/107  -> 400 NotAcceptableException
// after: grant user 107 Reader role on project first (Admin > Project > Access Management), then
POST /~api/pull-requests/42/reviewers/107  -> 200 OK
Defensive patterns

Strategy: validation

Validate before calling

// Check the candidate reviewer has read access before calling the API
const canRead = await onedevApi.projectQueryPermission(projectId, "READ_CODE", reviewerUserId);
if (!canRead || reviewerUserId === pr.submitter.id) {
  throw new Error(`User ${reviewerUserId} cannot review project ${projectId}: grant READ_CODE first`);
}

Try / catch

try {
  await api.addReviewer(requestId, userId);
} catch (e) {
  if (e.status === 400 && /read code permission/.test(e.body)) {
    // grant read permission or choose another reviewer
  } else throw e;
}

Prevention

When it happens

Trigger: Calling addReviewer (POST .../reviewers/{userId}) where SecurityUtils.canReadCode(user.asSubject(), request.getProject()) returns false — i.e. the nominated user has no Reader role or higher on the target project (e.g. a logged-in user with no project membership, or a user of another project).

Common situations: Admin adds a reviewer from a different project/team who was never granted access; project ACL was tightened and previously-addable users became ineligible; automation scripts pick arbitrary user IDs; a guest-level account is nominated.

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