{"record":{"id":"d13b15b45b34374c","repo":"theonedev/onedev","slug":"code-write-permission-is-required-to-edit-auto-mer","errorCode":null,"errorMessage":"Code write permission is required to edit auto merge","messagePattern":"Code write permission is required to edit auto merge","errorType":"http","errorClass":"UnauthorizedException","httpStatus":403,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/TodResource.java","lineNumber":1432,"sourceCode":"                    review.setStatus(PullRequestReview.Status.EXCLUDED);\n                    excludedReviews.add(review);\n                }\n            }\n            pullRequestService.checkReviews(request, false);\n            var requiredReviewers = excludedReviews.stream()\n                    .filter(it -> it.getStatus() != PullRequestReview.Status.EXCLUDED)\n                    .map(it -> it.getUser().getName())\n                    .collect(Collectors.toList());\n            if (!requiredReviewers.isEmpty())\n                throw new NotAcceptableException(\"Unable to remove mandatory reviewers: \" + String.join(\", \", requiredReviewers));\n            for (var review : excludedReviews) \n                pullRequestReviewService.createOrUpdate(user, review);\n        }\n\n        var autoMergeEnabled = (Boolean) data.remove(\"autoMerge\");\n        if (autoMergeEnabled != null) {\n            if (!SecurityUtils.canWriteCode(request.getProject()))\n                throw new UnauthorizedException(\"Code write permission is required to edit auto merge\");\n            if (!request.isOpen())\n                throw new NotAcceptableException(\"Pull request is closed\");\n\n            if (autoMergeEnabled && request.checkMergeCondition() == null) \n                throw new NotAcceptableException(\"This pull request is not eligible for auto-merge, as it can be merged directly now\");\n\n            var autoMerge = new AutoMerge();\n            autoMerge.setEnabled(autoMergeEnabled);\n            autoMerge.setCommitMessage(trimToNull((String) data.remove(\"autoMergeCommitMessage\")));\n            var errorMessage = request.checkMergeCommitMessage(user, autoMerge.getCommitMessage());\n            if (errorMessage != null) \n                throw new NotAcceptableException(\"Error validating param auto merge commit message: \" + errorMessage);\n\n            pullRequestChangeService.changeAutoMerge(user, request, autoMerge);\n        }\n                    \n        return PullRequestHelper.getDetail(currentProject, request);        \n    }    ","sourceCodeStart":1414,"sourceCodeEnd":1450,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/TodResource.java#L1414-L1450","documentation":"Toggling the 'autoMerge' field requires code write permission on the pull request's project, checked via SecurityUtils.canWriteCode(). The current authenticated user lacks that permission, so the endpoint throws UnauthorizedException before any state checks.","triggerScenarios":"POST /edit-pull-request with a non-null 'autoMerge' value while the caller is authenticated as a user without write access to the project's code (e.g. read-only role or non-member).","commonSituations":"AI agents or bots running with restricted tokens trying to enable auto-merge; users with only read/reporter roles attempting auto-merge via API; token scoped to a project where the identity lacks commit rights.","solutions":["Grant the user (or the bot's account) code write permission on the project (Project -> Access Control).","Perform the auto-merge edit with an account/token that has write access.","If the caller should not have write access, have an authorized user toggle auto-merge instead.","Drop the 'autoMerge' field from the request if only other fields (title, labels, etc.) need editing."],"exampleFix":"// before\n// bot token with read-only role calls:\nawait editPullRequest(ref, { autoMerge: true });\n// after\n// use a service account with code write permission, or skip:\nif (await canWriteCode(project)) {\n  await editPullRequest(ref, { autoMerge: true });\n}","handlingStrategy":"try-catch","validationCode":"// client-side pre-check\nconst perms = await getMyProjectPermissions(project);\nif (!perms.includes('write code')) throw new Error('autoMerge requires code write permission');","typeGuard":"function canEditAutoMerge(perms) { return perms.includes('write'); }","tryCatchPattern":"try {\n  await editPullRequest(ref, { autoMerge: true });\n} catch (e) {\n  if (e.status === 401 || e.status === 403) {\n    // request elevation or fall back to a service account with write access\n  }\n}","preventionTips":["Provision bots/service accounts with the minimum required write permission before enabling auto-merge via API.","Check the caller's effective permissions before sending 'autoMerge'.","Keep auto-merge toggling to accounts with code write rights.","Omit 'autoMerge' from requests made by read-only identities."],"tags":["rest","permissions","auto-merge","authorization"],"backgroundTag":"permission-denied","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"}