{"record":{"id":"70cd431c938a7995","repo":"gitbutlerapp/gitbutler","slug":"failed-to-merge-pull-request-status-error-te","errorCode":null,"errorMessage":"Failed to merge pull request: {status} - {error_text}","messagePattern":"Failed to merge pull request: (.+?) - (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-bitbucket/src/client.rs","lineNumber":461,"sourceCode":"        Ok(())\n    }\n\n    pub async fn merge_pull_request(&self, params: &MergePullRequestParams<'_>) -> Result<()> {\n        let body = MergePullRequestBody {\n            merge_strategy: params.strategy.as_str(),\n        };\n        let url = format!(\n            \"{}/repositories/{}/{}/pullrequests/{}/merge\",\n            self.base_url,\n            urlencoding::encode(params.workspace),\n            urlencoding::encode(params.repo_slug),\n            params.id,\n        );\n        let response = self.client.post(&url).json(&body).send().await?;\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 merge pull request: {status} - {error_text}\");\n        }\n        Ok(())\n    }\n\n    /// Decline (close) a pull request.\n    pub async fn decline_pull_request(\n        &self,\n        workspace: &str,\n        repo_slug: &str,\n        id: i64,\n    ) -> Result<()> {\n        let url = format!(\n            \"{}/repositories/{}/{}/pullrequests/{}/decline\",\n            self.base_url,\n            urlencoding::encode(workspace),\n            urlencoding::encode(repo_slug),\n            id,\n        );","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-bitbucket/src/client.rs#L443-L479","documentation":"Thrown by merge_pull_request when the HTTP POST that merges a Bitbucket pull request returns a non-success status. The message carries the HTTP status plus Bitbucket's response body, which typically explains why the merge was rejected (conflicts, unmet checks, insufficient merge strategies).","triggerScenarios":"Merging a PR that is not open (404/400), unresolved merge conflicts (400), failing required build checks or merge checks, token without write/merge permission (403), or a merge strategy the repository disallows.","commonSituations":"Attempting to merge after the branch moved and conflicts appeared; required CI checks failing; user token lacking merge rights; PR already merged by someone else concurrently.","solutions":["Read the error_text in the message — it names the failing merge check or conflict","Re-run/repair CI checks on the PR's source commit before merging","Pull/resolve merge conflicts on the source branch and push, then retry","Ensure the token/account has merge permission on the repository"],"exampleFix":"// before\nclient.merge_pull_request(workspace, repo_slug, id, params).await?;\n// after\nmatch client.merge_pull_request(workspace, repo_slug, id, params).await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"409\") => anyhow::bail!(\"PR #{id} has conflicts; resolve and retry\"),\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":"// pre-check: required checks green and PR open\nlet pr_state = get_pr_state(ws, slug, id)?;\nanyhow::ensure!(pr_state == \"OPEN\", \"PR #{id} is not open for merge\");","typeGuard":null,"tryCatchPattern":"match client.merge_pull_request(ws, slug, id, params).await {\n    Err(e) if e.to_string().contains(\"conflict\") || e.to_string().contains(\"400\") => resolve_conflicts_then_retry()?,\n    other => other?,\n}","preventionTips":["Verify CI checks pass before merging","Refresh the source branch and resolve conflicts before merge attempts","Ensure the account has merge permission","Handle 'already merged' errors as idempotent success in automation"],"tags":["network","http","bitbucket","pull-request","merge"],"backgroundTag":"upstream-api-error","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"}