GitLab: why the rebase did not happen
Rebasing a merge request through the API (PUT /projects/:id/merge_requests/:merge_request_iid/rebase) is refused at once with 403 or 409, or answers 202, which only means that GitLab has queued the rebase: it runs afterwards and can still fail. All of this is from GitLab's source (the rebase endpoint in lib/api/merge_requests.rb, MergeRequests::RebaseService, and rebase_async in app/models/merge_request.rb), read on October 24, 2026.
The answers
- 403
{"message":"403 Forbidden - Cannot push to source branch"}: your account may not push to the source branch, in the project the branch is in (for a merge request from a fork, the fork). A rebase rewrites that branch, so GitLab asks for the same right as a push. - 403
403 Forbidden - Source branch is protected from force push: the source branch is protected, and its protection does not allow force push. A rebase replaces the branch's commits, which is a force push. - 403
403 Forbidden - Source branch does not exist: the source branch has been deleted. GitLab's API documentation gives "You don't have permission to push" as the reason for this one too, but the source checks only whether the branch exists. - 409
{"message":"409 Conflict: Resource lock"}: the merge request is not open (closed, merged or locked), or a rebase of it is already queued or running. This answer is not in the API documentation. - 409
Failed to enqueue the rebase operation, possibly due to a long-lived transaction. Try again later.: GitLab could not lock the merge request within about 5 seconds.
After the 202 ({"rebase_in_progress":true}), a rebase that fails leaves its reason in the merge request's merge_error:
Rebase failed: Rebase locally, resolve all conflicts, then push the branch.: the source branch's commits do not apply cleanly onto the target branch. GitLab also gives this text for failures it does not explain.The rebase pre-receive hook failed: ….: the checks a push goes through before it is accepted (pre-receive) refused the rebased commits; the rest of the text is theirs.Rebase failed: ….with Git's own message: Git itself stopped.Source branch does not exist: the branch was deleted after the rebase was queued.
GitLab also writes a failed merge there. merge_error stays until the next push to the source branch, or until the merge request is closed or merged.
A token without the api scope is refused with 403 too, but that answer says insufficient_scope; see which scope to add. A project path that does not exist, or that you cannot see, answers 404; see address or permission.
Where it stands
curl -H "PRIVATE-TOKEN: your-token" "https://gitlab.com/api/v4/projects/group%2Fproject/merge_requests/42?include_rebase_in_progress=true"
While rebase_in_progress is true, the rebase is still queued or running. Once it is false, merge_error is null if the rebase worked, or says why it failed. state tells whether the merge request is still open. Use your own server's address instead of gitlab.com.
What to do
- 403 "Cannot push to source branch": ask a maintainer for the Developer role, or, if the branch is protected, for your role to be allowed to push to it. For a merge request from a fork, ask its author to rebase, or to select Allow commits from members who can merge to the target branch; GitLab's documentation says this is for forks that are publicly accessible, and that you then need the Developer role or higher in the project you merge into.
- 403 "protected from force push": a maintainer can allow force push in the branch's protection. Without it, bring in the target branch with a merge instead (
git fetch origin,git merge origin/main, then an ordinarygit push): in the source, GitLab asks for a rebase only while the target branch's latest commit is not in the source branch, and a merge puts it there. - 403 "Source branch does not exist": push the branch again (
git push -u origin feature), or close the merge request. - 409 "Resource lock": look at
state. If the merge request is open, a rebase is already under way: wait, and read the merge request again as above. - 409 "Failed to enqueue": try again in a moment.
- "Rebase failed: Rebase locally, resolve all conflicts…": do as it says:
git fetch origin,git rebase origin/main, resolve the conflicts, thengit push --force-with-lease. - "The rebase pre-receive hook failed": fix what the rest of the text names, then rebase again.
GitLab merge requests in IntelliJ IDEA
Merge Request Inbox for GitLab, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, offers to rebase the source branch when GitLab says the merge request needs a rebase. When GitLab answers 403, it says that your role in the project or its settings may not let your account do it, with GitLab's words; other refusals in GitLab's words. After the 202, it says that GitLab is rebasing the branch and to refresh in a moment; from version 1.0.14, when the rebase fails afterwards, the overview shows what GitLab put in merge_error, until the branch is pushed again or the merge request can be merged. Reading is free; rebasing, 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 merge refused (405, 409, 422) · GitLab auto-merge refused (405) or canceled · GitLab approval refused (401, 409) · GitLab comment or thread refused (400, 403) · GitLab merge request not created (409, 422, 400) · GitLab "insufficient_scope" · GitLab 401 "invalid_token" · GitLab 404 "Project Not Found" · 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 · 日本語