{"record":{"id":"8e0bf28dd505be2c","repo":"gitbutlerapp/gitbutler","slug":"failed-to-update-pull-request","errorCode":null,"errorMessage":"Failed to update pull request: {}","messagePattern":"Failed to update pull request: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":1442,"sourceCode":"            state: Option<&'a str>,\n        }\n\n        let url = format!(\n            \"{}/repos/{}/{}/pulls/{}\",\n            self.base_url, params.owner, params.repo, params.pr_number\n        );\n\n        let body = UpdatePullRequestBody {\n            title: params.title,\n            body: params.body,\n            base: params.base,\n            state: params.state,\n        };\n\n        let response = self.client.patch(&url).json(&body).send().await?;\n\n        if !response.status().is_success() {\n            bail!(\n                \"Failed to update pull request: {}\",\n                response_error(response).await\n            );\n        }\n\n        let pr: GitHubPullRequest = response.json().await?;\n        Ok(pr.into())\n    }\n\n    /// Merge a PR.\n    pub async fn merge_pull_request(&self, params: &MergePullRequestParams<'_>) -> Result<()> {\n        #[derive(Serialize)]\n        struct MergePullRequestBody<'a> {\n            #[serde(skip_serializing_if = \"Option::is_none\")]\n            commit_title: Option<&'a str>,\n            #[serde(skip_serializing_if = \"Option::is_none\")]\n            commit_message: Option<&'a str>,\n            #[serde(skip_serializing_if = \"Option::is_none\")]","sourceCodeStart":1424,"sourceCodeEnd":1460,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L1424-L1460","documentation":"The GitHub REST PATCH call used to update a pull request (title, body, state, etc.) returned a non-success HTTP status. The library bails with the response body (rendered via response_error) so you can see GitHub's actual rejection reason. It signals the update request itself failed server-side, not a local validation problem.","triggerScenarios":"Calling update_pull_request with parameters GitHub rejects: nonexistent PR number, wrong owner/repo, token lacking write access to the repo or PR, closed PRs receiving state changes not allowed, invalid field values, or network/429/5xx responses.","commonSituations":"Using a fine-grained PAT without pull request write permission; stale PR numbers after rebase/force-push cleanup; typos in owner/repo; hitting rate limits during automation loops; trying to update a PR in an archived repository.","solutions":["Read the appended response_error output to see GitHub's concrete reason and fix the request field it names","Verify the token has repo/pull-requests write scope (classic) or Pull requests: write (fine-grained)","Confirm the PR number exists in owner/repo (e.g. via gh pr view or get_pull_request)","Check for 403/429 rate-limit or SSO issues and retry after the rate-limit reset"],"exampleFix":"// before\nclient.update_pull_request(&UpdatePullRequestParams { owner, repo, pr_number: 0, .. }).await?;\n// after\nif pr_number > 0 {\n    client.update_pull_request(&UpdatePullRequestParams { owner, repo, pr_number, .. }).await?;\n}","handlingStrategy":"try-catch","validationCode":"// before calling: ensure the PR exists and the token can write\nlet pr = client.get_pull_request(owner, repo, pr_number).await?;\nassert!(pr_number > 0);","typeGuard":null,"tryCatchPattern":"// Rust: match on the error and inspect the embedded GitHub response body\nmatch client.update_pull_request(&params).await {\n    Ok(pr) => pr,\n    Err(e) if e.to_string().contains(\"Failed to update pull request\") => {\n        eprintln!(\"GitHub rejected the update: {e}\");\n        // 403 -> check token scopes; 404 -> check owner/repo/number\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Grant the token Pull requests: write before automation runs","Fetch the PR first to confirm it exists and is mutable","Handle 429/403 rate-limit responses with backoff","Log the full response_error body so GitHub's reason is never swallowed"],"tags":["github","rest","http","pull-request"],"backgroundTag":"http-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"}