GitLab: why the merge was refused
When a merge through the API fails, GitLab answers with one of five statuses, and each means something different. From GitLab's merge API, checked against its source (lib/api/merge_requests.rb): 405 means that a merge check stops the merge request right now, 409 that the source branch moved, 422 that the merge itself failed, 401 that your account may not merge into the target branch, and 400 that the group or instance requires the commit SHA.
The answers
- 405
{"message":"405 Method Not Allowed"}: the merge request cannot be merged now. Something in its merge checks stops it; see below. - 409
SHA does not match HEAD of source branch: …: the request named the commit the reviewer saw, and the source branch has another head now (GitLab adds the new one after the colon). Someone pushed after you looked. - 422
Branch cannot be merged: GitLab tried and the merge did not happen. In the source, this is when the merge request turns out not to be mergeable at the last moment, or the merge service did not merge it. - 401
401 Unauthorized: in this endpoint, not a bad token. GitLab checks whether your account may update the target branch (can_be_merged_by?), so, for example, a protected branch that your role may not merge into answers 401. - 400
SHA must be provided when merging: the group or instance setting require a commit SHA on the merge requests API is on, and the request did not name one.
Which merge check stops it (405)
Read the merge request and look at detailed_merge_status:
curl -H "PRIVATE-TOKEN: your-token" "https://gitlab.com/api/v4/projects/group%2Fproject/merge_requests/42"
Some of its values, from GitLab's merge status list:
draft_status: it is a draft. Mark it as ready.not_approved: approvals are still required.requested_changes: a reviewer requested changes.discussions_not_resolved: all threads must be resolved first.ci_must_passorci_still_running: the pipeline must succeed first.conflict: the source and target branches conflict.need_rebase: the source branch must be rebased onto the target.not_open: it is not open.merge_request_blocked: another merge request must be merged first.checking,uncheckedorpreparing: GitLab has not finished checking. The check runs in the background, so read it again a moment later.
The list also has statuses for status checks, security policies, locked files and paths, a required Jira issue and a title pattern. Asking to merge automatically (auto_merge) instead merges it once the checks pass; it has a 405 of its own, see what auto-merge waits for.
What to do
- 405: fix what
detailed_merge_statusnames, then merge again. - 409: look at the new commits, then merge with the new head.
- 422: read the merge request again: if it now says
conflictorneed_rebase, resolve or rebase first. - 401: ask a maintainer, or check who may merge into the target branch under Settings > Repository > Protected branches.
- 400: send
shawith the head commit you reviewed.
In IntelliJ IDEA: "Review has conversations that must be resolved" and "Source branch must be rebased before merging"
The GitLab merge requests built into IntelliJ IDEA show these two lines in a merge request's status. In the source (checked October 30, 2026):
- "Review has conversations that must be resolved" shows when the target project has All threads must be resolved turned on (GraphQL
onlyAllowMergeIfAllDiscussionsAreResolved) and at least one thread of the merge request that can be resolved is not resolved; a standard comment, which cannot be resolved until someone replies to it, does not count (GitLabMergeRequestStatusViewModel.kt, GitLabMergeRequestDiscussionUtil.kt). It is the case GitLab callsdiscussions_not_resolved. The setting is under Settings > Merge requests > Merge checks (GitLab: Prevent merge unless all threads are resolved). A report that the line showed all the time was marked fixed on May 29, 2024 (IJPL-81324). - "Source branch must be rebased before merging" shows, with a Rebase button, when the merge request is open, you can merge it, the target project merges by fast-forward (
mergeRequestsFfOnlyEnabled), and GitLab says the source branch has to be rebased (shouldBeRebased). It is the case GitLab callsneed_rebase: a fast-forward merge is only possible when the target branch has no commits that the source branch lacks (GitLab: Fast-forward merge). Rebase asks GitLab to rebase the source branch on the server (PUT /projects/:id/merge_requests/:merge_request_iid/rebase) and reloads the merge request while GitLab says the rebase is in progress; nothing happens in your local clone (GitLabMergeRequestDetailsStatusChecksComponentFactory.kt, GitLabMergeRequestFullDetails.kt, GitLabMergeRequest.kt). When GitLab does not rebase, see why the rebase did not happen.
In IntelliJ IDEA: "All required checks have passed", "Checks in progress…" and "Checks failed"
The GitLab merge requests built into IntelliJ IDEA also put one line for the pipeline in a merge request's status, with a Details… link to its jobs. In the source (checked October 30, 2026), the line reads the jobs of the merge request's head pipeline (up to 1,000), and a job counts as required unless it is allowed to fail (allowFailure):
- "All required checks have passed" when every required job succeeded, also when no job is required.
- Otherwise "Checks in progress, and some already failed…" when a job is still in progress and a job failed, "Checks in progress…" when a job is in progress and none failed, and "Checks failed" in every other case.
- Failed and canceled jobs count as failed; created, pending, preparing, running, scheduled and waiting-for-resource jobs count as in progress. Manual and skipped jobs are neither, so a required job that is manual or skipped, with nothing running or failed, makes the line read "Checks failed". A manual job is required when it has
allow_failure: false, the default forwhen: manualinsiderules(a blocking manual job: the pipeline stops at its stage until someone runs it); outsiderules, a manual job is allowed to fail by default (GitLab: allow_failure, Types of manual jobs; IntelliJ IDEA: GitLabMergeRequestStatusViewModel.kt, pipeline.graphql, CodeReviewDetailsStatusComponentFactory.kt). - Without a head pipeline, or with a pipeline without jobs, the line is not shown.
In IntelliJ IDEA: "Branch has conflicts that must be resolved"
The GitLab merge requests built into IntelliJ IDEA also show "Branch has conflicts that must be resolved" in a merge request's status, with a Resolve link. In the source (checked October 30, 2026), the line follows the merge status GraphQL gives (mergeStatusEnum): CANNOT_BE_MERGED ("There are conflicts between the source and target branches") shows it; CHECKING, UNCHECKED and CANNOT_BE_MERGED_RECHECK ("Currently unchecked. The previous state was CANNOT_BE_MERGED"), and the time before the details have loaded, show "Checking branch for conflicts" instead; CAN_BE_MERGED hides it (GitLab: MergeStatus; IntelliJ IDEA: GitLabResolveConflictsLocallyViewModel.kt, GitLabMergeRequestFullDetails.kt, GitLabMergeRequestDetailsStatusChecksComponentFactory.kt, CodeReviewDetailsStatusComponentFactory.kt). Resolve asks whether to rebase or merge, fetches the target branch, checks out the source branch (adding a remote for the source project when it is a fork your clone does not have yet), and then, in your local clone, rebases the source branch onto the target branch or merges the target branch into it. Any conflicts are then resolved in the IDE, and the merge request changes only when you push; after a rebase, that push has to be a force push (ResolveConflictsLocallyViewModel.kt). Resolve is greyed out, with the reason on it, while the repository is in the middle of a merge or a rebase ("Merge is already in progress"), when GitLab gives no source project ("The source project is private or does not exist"), and when the current branch already tracks the source branch and has the commit GitLab gives as the base of the diff (diffRefs baseSha, "Merge base of the branch the comment was made on") in its history ("Already resolved locally, push your changes to resolve") (CollaborationToolsBundle.properties, GitLabBundle.properties, GitLabResolveConflictsLocallyViewModel.kt).
GitLab merge requests in IntelliJ IDEA
Merge Request Inbox for GitLab, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, shows a merge request's merge checks before you merge: approvals, requested changes, unresolved threads, the pipeline, conflicts, and GitLab's other reasons from detailed_merge_status, with the ones that block the merge first. It merges the head commit you had on screen. When GitLab refuses, it says which case it is: for 405, that GitLab cannot merge it now and to see the merge checks; for 409, that the source branch changed and to refresh; for 422, that GitLab could not merge it, with GitLab's words; for 401, that your role or the project's settings may not allow it. When a rebase is needed, it offers one. Reading is free; approving, commenting and merging are Pro (US$1.50 a month, with a 30-day trial).
GITLAB is a trademark of GitLab Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with or endorsed by GitLab Inc. or JetBrains.
More: GitLab auto-merge refused (405) or canceled · GitLab 404 "Project Not Found" · GitLab "insufficient_scope" · GitLab 401 "invalid_token" · GitLab approval refused (401, 409) · GitLab comment or thread refused (400, 403) · GitLab merge request not created (409, 422, 400) · GitLab rebase refused or failed (403, 409) · GitLab merge request list refused (400, 404) · GitLab merge request changes cut short ("1000+", too_large) · GitLab 429 "Retry later" (rate limits) · GitLab merge refused or failed over squashing · GitLab "compare_timeout": true (diff limits) · GitLab merge request plugins for IntelliJ IDEA, compared · 日本語