theonedev/onedev · warning · NotAcceptableException

This pull request is not eligible for auto-merge, as it can

Error message

This pull request is not eligible for auto-merge, as it can be merged directly now

What it means

Thrown by POST /pull-requests/{requestId}/auto-merge when enabling auto-merge on a PR that already satisfies its merge condition, meaning it can be merged immediately and auto-merge is pointless. OneDev deliberately rejects this via NotAcceptableException (HTTP 406) to force a direct merge instead.

Source

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

			throw new NotAcceptableException("Pull request is closed");
		pullRequestChangeService.changeMergeStrategy(user, request, mergeStrategy);
		return Response.ok().build();
    }
	
	@Api(order=1550)
	@Path("/{requestId}/auto-merge")
	@POST
	public Response setAutoMerge(@PathParam("requestId") Long requestId, @NotNull AutoMergeData data) {
		var subject = SecurityUtils.getSubject();
		var user = SecurityUtils.getUser(subject);
		PullRequest request = pullRequestService.load(requestId);
		if (!SecurityUtils.canModifyPullRequest(subject, request) || !SecurityUtils.canWriteCode(subject, request.getProject()))
			throw new UnauthorizedException();
		if (!request.isOpen())
			throw new NotAcceptableException("Pull request is closed");

		if (data.isEnabled() && request.checkMergeCondition() == null)
			throw new NotAcceptableException("This pull request is not eligible for auto-merge, as it can be merged directly now");

		var autoMerge = new AutoMerge();
		autoMerge.setEnabled(data.isEnabled());
		autoMerge.setCommitMessage(data.getCommitMessage());
		var errorMessage = request.checkMergeCommitMessage(user, autoMerge.getCommitMessage());
		if (errorMessage != null)
			throw new NotAcceptableException("Error validating auto merge commit message: " + errorMessage);

		pullRequestChangeService.changeAutoMerge(user, request, autoMerge);

		return Response.ok().build();
	}
	
	@Api(order=1600)
	@Path("/{requestId}/reopen")
    @POST
    public Response reopenPullRequest(@PathParam("requestId") Long requestId, String note) {
		PullRequest request = pullRequestService.load(requestId);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Call the merge endpoint (POST /~api/pull-requests/{requestId}/merge) directly instead of enabling auto-merge
  2. Check merge eligibility first and branch: merge now if eligible, else enable auto-merge
  3. Re-run the call only for PRs with an actual blocking condition
  4. Fix automation logic to treat 'mergeable' as 'merge now'

Example fix

// before
post('/~api/pull-requests/' + id + '/auto-merge', {enabled: true})
// after
var pr = get('/~api/pull-requests/' + id)
if (pr.mergeConditionSatisfied)
  post('/~api/pull-requests/' + id + '/merge')
else
  post('/~api/pull-requests/' + id + '/auto-merge', {enabled: true})
Defensive patterns

Strategy: validation

Validate before calling

var pr = get('/~api/pull-requests/' + id)
if (pr.mergeable === true) { // eligible to merge directly
  post('/~api/pull-requests/' + id + '/merge');
  return;
}
post('/~api/pull-requests/' + id + '/auto-merge', {enabled: true})

Type guard

function shouldAutoMerge(pr) { return !!pr && pr.status === 'OPEN' && pr.mergeable === false; }

Try / catch

try {
  post('/~api/pull-requests/' + id + '/auto-merge', {enabled: true});
} catch (e) {
  if (e.status === 406 && /merged directly/i.test(e.body || '')) {
    post('/~api/pull-requests/' + id + '/merge'); // merge now instead
  } else throw e;
}

Prevention

When it happens

Trigger: POSTing {enabled:true} to /~api/pull-requests/{requestId}/auto-merge when request.checkMergeCondition() returns null — i.e. no build failures, no unresolved required reviews, branch up to date, all merge prerequisites already met.

Common situations: Enabling auto-merge by default in scripts even for PRs whose CI already passed and reviews are complete; race where the last blocking condition clears just before the auto-merge call; automation that should merge directly instead of scheduling.

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


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/955f82a1a54ff82e. Report an issue: GitHub.