gitbutlerapp/gitbutler · error
Failed to enable merge request auto-merge
Error message
Failed to enable merge request auto-merge: {status} - {error_text} What it means
set_merge_request_auto_merge calls the GitLab auto-merge endpoint (POST .../merge_trains or /auto_merge per instance version). A non-2xx response bails with the status and GitLab's error body. GitLab rejects auto-merge when the MR is not currently mergeable or when merge trains are not enabled for the project.
Solutions
- Inspect the embedded error_text: 400/405 commonly means merge trains are disabled or the merge_status is `not_open`/`checking`.
- Verify the MR's `merge_status` is `can_be_merged` and pipeline status before enabling auto-merge; retry after pipeline finishes.
- Use the correct auto_merge_strategy for the project config (`merge_train_when_pipeline_succeeds` only with merge trains enabled).
- Check the user has Developer+ role and the target branch protection allows their merges.
- Treat 404/405 on old GitLab instances as 'feature unsupported' and fall back to polling-and-merging.
Example fix
// before
client.set_merge_request_auto_merge(project_id, iid, strategy).await?;
// after
let mr = client.get_merge_request(project_id, iid).await?;
if mr.merge_status == "can_be_merged" {
client.set_merge_request_auto_merge(project_id, iid, strategy).await?;
} else {
// wait for pipeline / discussions to resolve first
} Defensive patterns
Strategy: try-catch
Validate before calling
let mr = client.get_merge_request(project_id, mr_iid).await?;
if mr.merge_status != "can_be_merged" || mr.draft || mr.blocking_discussions_resolved != Some(true) {
return Err(anyhow!("MR not eligible for auto-merge yet"));
} Try / catch
match client.set_merge_request_auto_merge(project_id, iid, strategy).await {
Err(e) if e.to_string().contains("405") || e.to_string().contains("400") => {
// merge trains disabled or MR not open: fall back to polling + merge
}
Err(e) => return Err(e),
Ok(()) => {}
} Prevention
- Confirm the project has merge trains enabled before using merge-train strategies
- Wait for the pipeline to reach a pending/running success path before enabling auto-merge
- Check merge_status == "can_be_merged" first
- Handle 'already merged' races by re-reading MR state after the error
When it happens
Trigger: Enabling auto-merge on an MR whose pipeline hasn't started/failed `merge_status` checks, when the project has merge trains disabled (GitLab returns 400/405), when the MR has unresolved discussions, or when the token lacks merge permission. Also triggered when the auto-merge strategy payload is invalid for the instance's GitLab version.
Common situations: Project recently switched between merge trains and simple auto-merge, so the chosen strategy is no longer valid; MR not yet ready when the client fires the call; free-tier project without merge-train feature; race where the MR gets merged before auto-merge is set.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed to disable merge request auto-merge
- Failed to merge merge request
- Failed to set merge request draft state
- Failed to create merge request
- Failed to fetch project
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/67654c97375efb07.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-gitlab/src/client.rs:566
auto_merge: bool,
}
let url = format!(
"{}/projects/{}/merge_requests/{}/merge",
self.base_url, project_id, params.mr_iid
);
let response = self
.client
.put(&url)
.json(&EnableAutoMergeBody { auto_merge: true })
.send()
.await?;
if !response.status().is_success() {
let status = response.status();
let error_text = response.text().await.unwrap_or_default();
bail!("Failed to enable merge request auto-merge: {status} - {error_text}");
}
return Ok(());
}
let url = format!(
"{}/projects/{}/merge_requests/{}/cancel_merge_when_pipeline_succeeds",
self.base_url, project_id, params.mr_iid
);
let response = self.client.post(&url).send().await?;
if !response.status().is_success() {
let status = response.status();
let error_text = response.text().await.unwrap_or_default();
bail!("Failed to disable merge request auto-merge: {status} - {error_text}");
}
View on GitHub (pinned to 58e5313667)