{"record":{"id":"faf54fa4c2b67e09","repo":"gitbutlerapp/gitbutler","slug":"failed-to-request-reviewers","errorCode":null,"errorMessage":"Failed to request reviewers: {}","messagePattern":"Failed to request reviewers: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":886,"sourceCode":"        owner: &str,\n        repo: &str,\n        pr_number: i64,\n        reviewers: &[String],\n    ) -> Result<()> {\n        let url = format!(\n            \"{}/repos/{}/{}/pulls/{}/requested_reviewers\",\n            self.base_url, owner, repo, pr_number\n        );\n\n        let response = self\n            .client\n            .post(&url)\n            .json(&ReviewersBody { reviewers })\n            .send()\n            .await?;\n\n        if !response.status().is_success() {\n            bail!(\n                \"Failed to request reviewers: {}\",\n                response_error(response).await\n            );\n        }\n\n        Ok(())\n    }\n\n    pub async fn remove_requested_reviewers(\n        &self,\n        owner: &str,\n        repo: &str,\n        pr_number: i64,\n        reviewers: &[String],\n    ) -> Result<()> {\n        let url = format!(\n            \"{}/repos/{}/{}/pulls/{}/requested_reviewers\",\n            self.base_url, owner, repo, pr_number","sourceCodeStart":868,"sourceCodeEnd":904,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L868-L904","documentation":"This error comes from `GithubClient::request_reviewers`, which POSTs to the GitHub REST endpoint `/repos/{owner}/{repo}/pulls/{n}/requested_reviewers`. When GitHub returns any non-2xx status, the client reads the error body via `response_error` and bails with this message. It means the review-request mutation was rejected by GitHub, so no reviewers were requested.","triggerScenarios":"Any `request_reviewers(owner, repo, pr_number, reviewers)` call where the POST to `/repos/{owner}/{repo}/pulls/{pr_number}/requested_reviewers` returns a non-success status — e.g. 401/403 (bad token or missing `pull-requests: write`), 404 (wrong owner/repo/PR number), 422 (reviewer cannot be requested: not a collaborator, already requested, or the Copilot bot cannot be assigned), or 403 rate limiting.","commonSituations":"Requesting a user who is not a collaborator and was never a comment author on the PR; using a fine-grained PAT without pull-request write permission; the PR number being from a different fork/repo; organization restrictions blocking outside reviewers; requesting `copilot-pull-request-reviewer[bot]` on a repo where the Copilot reviewer app is not installed.","solutions":["Read the embedded GitHub error body in the message to see the exact status and reason.","Verify the token has write access on pull requests for the repository (classic: `repo` scope; fine-grained: Pull requests: Read and write).","Confirm the reviewers are collaborators or previously commented on the PR; otherwise add them first or use the correct login.","Check owner/repo/pr_number resolve to an existing PR (`GET /repos/{owner}/{repo}/pulls/{n}`).","If status 403 with `X-RateLimit-Remaining: 0`, wait for the rate-limit window to reset before retrying."],"exampleFix":"// before\nclient.request_reviewers(\"acme\", \"api\", 42, &[\"randomuser\".into()]).await?; // 422: not a collaborator\n// after\n// ensure the user is a collaborator, or fall back to mentioning them\nif client.is_collaborator(\"acme\", \"api\", \"randomuser\").await.unwrap_or(false) {\n    client.request_reviewers(\"acme\", \"api\", 42, &[\"randomuser\".into()]).await?;\n} else {\n    // comment @randomuser instead of requesting them\n}","handlingStrategy":"try-catch","validationCode":"if reviewers.is_empty() { return Err(anyhow!(\"no reviewers given\")); }\nlet pr = client.get_pull_request(owner, repo, pr_number).await?; // 404 check before mutation\nfor r in reviewers {\n    if !client.is_collaborator(owner, repo, r).await.unwrap_or(false) {\n        return Err(anyhow!(\"{r} is not a collaborator of {owner}/{repo}\"));\n    }\n}","typeGuard":"fn is_ok_status(status: reqwest::StatusCode) -> bool { status.is_success() }","tryCatchPattern":"match client.request_reviewers(owner, repo, pr, &reviewers).await {\n    Ok(()) => info!(\"reviewers requested\"),\n    Err(e) if e.to_string().contains(\"422\") => warn!(\"reviewer not requestable, skipping: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Check reviewer collaboration status before requesting.","Ensure the token has pull-request write scope for the repo.","Verify PR coordinates (owner/repo/number) before mutations.","Log the GitHub error body embedded in the message for diagnosis."],"tags":["github-api","http-error-response","network","rest"],"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"}