{"record":{"id":"fbd50ca4e206a8d0","repo":"theonedev/onedev","slug":"another-pull-request-already-merged-the-change","errorCode":null,"errorMessage":"Another pull request already merged the change","messagePattern":"Another pull request already merged the change","errorType":"validation","errorClass":"NotAcceptableException","httpStatus":400,"severity":"info","filePath":"server-core/src/main/java/io/onedev/server/service/impl/DefaultPullRequestService.java","lineNumber":447,"sourceCode":"\t\t\t\t\"Pull request target must be set before calling open\");\n\t\tvar source = Preconditions.checkNotNull(request.getSource(),\n\t\t\t\t\"Pull request source must be set before calling open\");\n\t\tPreconditions.checkNotNull(request.getSubmitter(),\n\t\t\t\t\"Pull request submitter must be set before calling open\");\n\n\t\tif (target.equals(source))\n\t\t\tthrow new NotAcceptableException(\"Source and target are the same\");\n\n\t\tPullRequest existing = findOpen(target, source);\n\t\tif (existing != null)\n\t\t\tthrow new NotAcceptableException(\"Another pull request already opened for this change\");\n\n\t\texisting = findEffective(target, source);\n\t\tif (existing != null) {\n\t\t\tif (existing.isOpen())\n\t\t\t\tthrow new NotAcceptableException(\"Another pull request already opened for this change\");\n\t\t\telse\n\t\t\t\tthrow new NotAcceptableException(\"Another pull request already merged the change\");\n\t\t}\n\n\t\tif (request.getBaseCommitHash() == null) {\n\t\t\tObjectId baseCommitId = gitService.getMergeBase(\n\t\t\t\t\ttarget.getProject(), target.getObjectId(),\n\t\t\t\t\tsource.getProject(), source.getObjectId());\n\t\t\tif (baseCommitId == null)\n\t\t\t\tthrow new NotAcceptableException(\"No common base for target and source\");\n\t\t\trequest.setBaseCommitHash(baseCommitId.name());\n\t\t}\n\n\t\tif (request.getBaseCommitHash().equals(source.getObjectName()))\n\t\t\tthrow new NotAcceptableException(\"Target already up to date with source\");\n\n\t\tif (request.getUpdates().isEmpty()) {\n\t\t\tPullRequestUpdate update = new PullRequestUpdate();\n\t\t\trequest.getUpdates().add(update);\n\t\t\trequest.setUpdates(request.getUpdates());","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/service/impl/DefaultPullRequestService.java#L429-L465","documentation":"DefaultPullRequestService.open() throws this when findEffective(target, source) returns a PR that is not open — meaning the same source->target change was already merged (or otherwise closed as effective). Creating a new PR would be pointless because the target already contains the change.","triggerScenarios":"Calling open() for a source branch whose changes were already merged into the target via a prior pull request (findEffective returns a closed/merged PR).","commonSituations":"CI auto-creating PRs from long-lived branches after the change was merged; user rebases a merged branch and retries; backport scripts re-opening PRs for already-merged commits.","solutions":["Check the existing effective PR and inform the user the change was already merged (link to it)","Fast-forward/delete the source branch or sync it with target so it no longer differs","Skip PR creation in automation when findEffective returns a merged PR","If a partial change remains, push new commits and a new branch before opening a PR"],"exampleFix":"// before\npullRequestService.open(request);\n// after\nPullRequest effective = pullRequestService.findEffective(target, source);\nif (effective != null && !effective.isOpen())\n    throw new SkipException(\"Change already merged in PR #\" + effective.getNumber());\npullRequestService.open(request);","handlingStrategy":"validation","validationCode":"PullRequest effective = pullRequestService.findEffective(target, source);\nif (effective != null && !effective.isOpen())\n    throw new SkipException(\"Already merged: PR #\" + effective.getNumber());","typeGuard":null,"tryCatchPattern":"try {\n    pullRequestService.open(request);\n} catch (NotAcceptableException e) {\n    if (e.getMessage().contains(\"already merged the change\"))\n        logger.info(\"Skipping: change already merged\");\n    else throw e;\n}","preventionTips":["Delete or archive source branches after merge so automation stops trying","Check findEffective before opening PRs from long-lived automation branches","Skip zero-diff branches before calling open()"],"tags":["pull-request","already-merged","onedev"],"backgroundTag":"invalid-state-transition","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"}