gitbutlerapp/gitbutler · error · anyhow::Error
Failed to update merge request: {status} - {error_text}
Error message
Failed to update merge request: {status} - {error_text} What it means
Thrown by GitLabClient::update_merge_request when the PUT to /projects/:id/merge_requests/:iid fails. Unlike most bails in this client it also forwards the response body (error_text), which contains GitLab's validation message, e.g. `{"message":"Target branch does not exist"}` — read it before doing anything else. The body updates title, description, target_branch and state_event (close/reopen) in one call.
Source
Thrown at crates/but-gitlab/src/client.rs:402
.await?;
Some(update_draft_state_in_title(title, mr.draft))
} else {
None
};
let body = UpdateMergeRequestBody {
title: title.as_deref(),
description: params.description,
target_branch: params.target_branch,
state_event: params.state_event,
};
let response = self.client.put(&url).json(&body).send().await?;
if !response.status().is_success() {
let status = response.status();
let error_text = response.text().await.unwrap_or_default();
bail!("Failed to update merge request: {status} - {error_text}");
}
let mr: GitLabMergeRequest = response.json().await?;
Ok(mr.into())
}
pub async fn merge_merge_request(&self, params: &MergeMergeRequestParams) -> Result<()> {
#[derive(Serialize)]
struct MergeMergeRequestBody {
#[serde(skip_serializing_if = "Option::is_none")]
squash: Option<bool>,
}
let url = format!(
"{}/projects/{}/merge_requests/{}/merge",
self.base_url, params.project_id, params.mr_iid
);
View on GitHub (pinned to caf1f223d3)
Solutions
- Read the {error_text} portion of the message — GitLab names the exact invalid field
- If target_branch is rejected, verify the branch exists (GET /projects/:id/repository/branches/:name) and re-run with the correct name
- Re-fetch the MR (get_merge_request) to confirm it still exists and is not already in the requested state before re-sending
- For 403, check the account's role on the project (Developer+ to edit MRs)
- Retry once after `but config forge auth` if 401
Example fix
// before
client.update_merge_request(¶ms).await?;
// after: guard the two common validation failures before the PUT
let mr = client.get_merge_request(project_id.clone(), mr_iid).await?;
if let Some(target) = params.target_branch {
ensure!(target.is_empty().not(), "target branch name must not be empty");
ensure!(mr.state == "opened", "cannot update a {} MR", mr.state);
}
client.update_merge_request(¶ms).await?; Defensive patterns
Strategy: validation
Validate before calling
// Reject the two common invalid payloads before the PUT
if let Some(branch) = params.target_branch {
ensure!(!branch.trim().is_empty(), "target branch must not be empty");
}
ensure!(matches!(params.state_event, None | Some("close") | Some("reopen")), "invalid state_event");
client.update_merge_request(¶ms).await?; Try / catch
if let Err(err) = client.update_merge_request(¶ms).await {
let msg = err.to_string();
if msg.contains("Target branch") { /* re-fetch branches, prompt user to pick again */ }
else { return Err(err); }
} Prevention
- Always read the {error_text} segment — GitLab names the offending field
- Re-fetch the MR before mutating to avoid stale-state updates (409-ish races)
When it happens
Trigger: PUT with target_branch set to a branch that no longer exists in the target project; state_event close/reopen on an MR in a conflicting state; title/description rejected by validation (e.g., empty title); 403 when the account lacks Developer rights to edit the MR; editing an MR that was just deleted (404).
Common situations: Retargeting an MR to a branch that was renamed or deleted by CI; automated title/description updates racing with the user closing the MR; permissions downgraded after the MR was opened; updating an MR on a fork whose upstream target moved.
Related errors
- Failed to get merge request: {}
- Failed to get MR merge status: {}
- Failed to merge merge request: {}
- Failed to set merge request draft state: {status} - {error_t
- Failed to enable merge request auto-merge: {status} - {error
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/41def527890e5a2c.
Report an issue: GitHub.