{"record":{"id":"41def527890e5a2c","repo":"gitbutlerapp/gitbutler","slug":"failed-to-update-merge-request-status-error","errorCode":null,"errorMessage":"Failed to update merge request: {status} - {error_text}","messagePattern":"Failed to update merge request: (.+?) - (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-gitlab/src/client.rs","lineNumber":468,"sourceCode":"                .await?;\n            Some(update_draft_state_in_title(title, mr.draft))\n        } else {\n            None\n        };\n\n        let body = UpdateMergeRequestBody {\n            title: title.as_deref(),\n            description: params.description,\n            target_branch: params.target_branch,\n            state_event: params.state_event,\n        };\n\n        let response = self.client.put(&url).json(&body).send().await?;\n\n        if !response.status().is_success() {\n            let status = response.status();\n            let error_text = response.text().await.unwrap_or_default();\n            bail!(\"Failed to update merge request: {status} - {error_text}\");\n        }\n\n        let mr: GitLabMergeRequest = response.json().await?;\n        Ok(mr.into())\n    }\n\n    pub async fn merge_merge_request(&self, params: &MergeMergeRequestParams) -> Result<()> {\n        #[derive(Serialize)]\n        struct MergeMergeRequestBody {\n            #[serde(skip_serializing_if = \"Option::is_none\")]\n            squash: Option<bool>,\n        }\n\n        let url = format!(\n            \"{}/projects/{}/merge_requests/{}/merge\",\n            self.base_url, params.project_id, params.mr_iid\n        );\n","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-gitlab/src/client.rs#L450-L486","documentation":"GitLab rejected the merge-request update PUT with a non-success HTTP status. The error message carries the status code and raw response body so the caller can identify whether it was authorization, validation, or a missing resource.","triggerScenarios":"Calling update_merge_request when PUT /projects/{id}/merge_requests/{mr_iid} returns 4xx/5xx — 404 for a wrong mr_iid or project, 400/422 for invalid field updates (bad target_branch, invalid state_event), 401/403 for token/permission problems.","commonSituations":"Updating an MR that was closed/deleted or whose IID changed after a project transfer; attempting to retarget to a nonexistent branch; token expired mid-session; trying to update MRs on protected branches without sufficient role.","solutions":["Read the embedded status and body for the exact GitLab error.","If 404, re-fetch the MR by IID to confirm it still exists in the project.","If 400/422, validate updated fields (e.g. target branch exists, state_event is 'close'/'reopen').","If 401/403, refresh the token and confirm write (Developer+ / Maintainer) access.","Retry with backoff on 5xx."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// validate the MR exists and fields are updatable before the PUT\nlet mr = gitlab.get_merge_request(project_id, mr_iid).await?; // 404 surfaces early\nanyhow::ensure!(mr.state == \"opened\", \"cannot update MR in state '{}'\", mr.state);\nif let Some(tb) = &new_target_branch {\n    anyhow::ensure!(branch_exists(project_id, tb).await?, \"target branch '{tb}' does not exist\");\n}","typeGuard":null,"tryCatchPattern":"match gitlab.update_merge_request(project_id, mr_iid, &body).await {\n    Ok(mr) => mr,\n    Err(e) if e.to_string().contains(\"404\") => refetch_mr_or_skip(),\n    Err(e) if e.to_string().contains(\"403\") => refresh_credentials(),\n    Err(e) => return Err(e),\n}","preventionTips":["Fetch the MR first to confirm it exists and is open before updating.","Validate any target branch change against the project's branch list.","Refresh tokens proactively in long-running sessions.","Check user role (Developer+/Maintainer) for MRs touching protected branches."],"tags":["gitlab","api","http","merge-request"],"backgroundTag":"api-error-response","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}