{"record":{"id":"0757b740c98b2f59","repo":"theonedev/onedev","slug":"reviewer-should-have-code-read-permission","errorCode":null,"errorMessage":"Reviewer should have code read permission: ","messagePattern":"Reviewer should have code read permission: ","errorType":"http","errorClass":"NotAcceptableException","httpStatus":406,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/PullRequestResource.java","lineNumber":292,"sourceCode":"\t\tif (!SecurityUtils.canReadCode(target.getProject()) || !SecurityUtils.canReadCode(source.getProject()))\n\t\t\tthrow new UnauthorizedException();\n\n\t\tPullRequest request = new PullRequest();\n\t\trequest.setSubmitter(user);\n\t\trequest.setTarget(target);\n\t\trequest.setSource(source);\n\t\trequest.setTitle(data.getTitle());\n\t\trequest.setDescription(data.getDescription());\n\t\tif (data.getMergeStrategy() != null)\n\t\t\trequest.setMergeStrategy(data.getMergeStrategy());\n\n\t\tif (data.getReviewerIds() != null) {\n\t\t\tfor (Long reviewerId: data.getReviewerIds()) {\n\t\t\t\tUser reviewer = userService.load(reviewerId);\n\t\t\t\tif (reviewer.equals(request.getSubmitter()))\n\t\t\t\t\treturn Response.status(NOT_ACCEPTABLE).entity(\"Pull request submitter cannot be reviewer\").build();\n\t\t\t\tif (!SecurityUtils.canReadCode(request.getProject()))\n\t\t\t\t\tthrow new NotAcceptableException(\"Reviewer should have code read permission: \" + reviewer.getName());\n\n\t\t\t\tif (request.getReview(reviewer) == null) {\n\t\t\t\t\tPullRequestReview review = new PullRequestReview();\n\t\t\t\t\treview.setRequest(request);\n\t\t\t\t\treview.setUser(reviewer);\n\t\t\t\t\trequest.getReviews().add(review);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (data.getAssigneeIds() != null && !data.getAssigneeIds().isEmpty()) {\n\t\t\tfor (Long assigneeId : data.getAssigneeIds()) {\n\t\t\t\tPullRequestAssignment assignment = new PullRequestAssignment();\n\t\t\t\tassignment.setRequest(request);\n\t\t\t\tvar assignee = userService.load(assigneeId);\n\t\t\t\tif (!SecurityUtils.canWriteCode(request.getProject()))\n\t\t\t\t\tthrow new NotAcceptableException(\"Assignee should have code write permission: \" + assignee.getName());\n\t\t\t\tassignment.setUser(assignee);","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/PullRequestResource.java#L274-L310","documentation":"When creating a pull request with reviewerIds, OneDev throws NotAcceptableException if a listed reviewer does not have code-read permission on the request's project (reviewers must be able to see the code they review). The message includes the offending reviewer's name.","triggerScenarios":"POST /~api/pull-requests with a reviewerIds entry for a user who is not a project member or lacks code-read; adding reviewers from another project/organization; reviewer account disabled or role downgraded.","commonSituations":"Auto-assigning default reviewer lists containing users outside the project; cross-team reviews where reviewers were never granted repo access; scripts copying reviewer sets from PRs in other projects.","solutions":["Remove users without project code-read from reviewerIds.","Grant each intended reviewer a role with code-read on the project before submitting.","Use users who can already open the project in the web UI as reviewers.","Split the flow: create the PR first, then add reviewers as their access is granted."],"exampleFix":"// before\n{\"reviewerIds\":[12,33]}   // user 33 has no access to the project\n// after\n{\"reviewerIds\":[12]}      // or grant user 33 code-read first","handlingStrategy":"validation","validationCode":"const reviewers = await Promise.all(ids.map(async id => {\n  const u = await (await fetch(`/~api/users/${id}`)).json()\n  return u\n}))\n// only pass reviewers who are project members with code-read\nconst eligible = reviewers.filter(u => projectMembers.some(m => m.id === u.id))","typeGuard":null,"tryCatchPattern":"try {\n  await api.post('/pull-requests', {...data, reviewerIds: ids})\n} catch (e) {\n  if (e.status === 400 && e.message.includes('Reviewer should have code read permission')) {\n    // strip the named reviewer and retry or surface to user\n  } else throw e\n}","preventionTips":["Maintain reviewer pick-lists sourced from project members only.","Sync reviewer defaults when users lose project access.","Exclude disabled/external accounts from reviewer pools.","Check the submitter is also not in reviewerIds."],"tags":["rest","validation","permissions","reviewers"],"backgroundTag":"insufficient-permissions","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}