theonedev/onedev · error · NotAcceptableException
Pull request already closed
Error message
Pull request already closed
What it means
discard throws this NotAcceptableException when the pull request is not open — it is already merged, discarded, or otherwise closed. A PR can only transition to DISCARDED from the OPEN state, so discarding a closed PR is rejected.
Source
Thrown at server-core/src/main/java/io/onedev/server/service/impl/DefaultPullRequestService.java:337
PullRequestChange change = new PullRequestChange();
change.setData(new PullRequestReopenData());
change.setRequest(request);
change.setUser(user);
changeService.create(change, note);
MergePreview mergePreview = request.checkMergePreview();
if (mergePreview != null)
updateMergePreviewRef(request);
checkAsync(request, false, true);
}
@Transactional
@Override
public void discard(User user, PullRequest request, String note) {
if (!request.isOpen())
throw new NotAcceptableException("Pull request already closed");
request.setStatus(Status.DISCARDED);
request.setCloseDate(new Date());
PullRequestChange change = new PullRequestChange();
change.setData(new PullRequestDiscardData());
change.setRequest(request);
change.setUser(user);
changeService.create(change, note);
pendingSuggestionApplyService.discard(null, request);
}
@Transactional
@Override
public void merge(User user, PullRequest request, @Nullable String commitMessage) {
var errorMessage = request.checkMergeCondition();
if (errorMessage != null)View on GitHub (pinned to d44925c47c)
Solutions
- Check request.isOpen() before calling discard and skip if already closed
- Treat the PR as already handled — no action needed if it was merged or discarded
- Handle the NotAcceptableException and read the PR's current status to decide next steps
Example fix
// before
prService.discard(user, request, "no longer needed"); // 400 "Pull request already closed"
// after
if (request.isOpen())
prService.discard(user, request, "no longer needed"); Defensive patterns
Strategy: validation
Validate before calling
boolean canDiscard = request.isOpen();
Try / catch
try {
prService.discard(user, request, note);
} catch (NotAcceptableException e) {
// PR already merged/discarded; no-op
} Prevention
- Always gate discard actions on request.isOpen()
- Disable discard buttons for closed PRs in UI
- Avoid replaying old discard requests in scripts
When it happens
Trigger: Calling DefaultPullRequestService.discard(user, request, note) when request.isOpen() is false — i.e. the PR status is MERGED, DISCARDED, or any non-open state. Also triggered via REST discard endpoint or checkAutoMerge's check path racing a concurrent close.
Common situations: Double-clicking / retrying a discard action; automation discarding PRs without checking state; a race where auto-merge merged the PR just before the discard call; REST scripts replaying old requests.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Pull request is closed
- Pull request is closed
- Reviewer not found:
- Pull request submitter cannot be reviewer
- Assignee not found:
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/2ecd1be198929cac.
Report an issue: GitHub.