gitbutlerapp/gitbutler · error
Failed to request reviewers
Error message
Failed to request reviewers: {} What it means
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.
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.
Example fix
// before
client.request_reviewers("acme", "api", 42, &["randomuser".into()]).await?; // 422: not a collaborator
// after
// ensure the user is a collaborator, or fall back to mentioning them
if client.is_collaborator("acme", "api", "randomuser").await.unwrap_or(false) {
client.request_reviewers("acme", "api", 42, &["randomuser".into()]).await?;
} else {
// comment @randomuser instead of requesting them
} Defensive patterns
Strategy: try-catch
Validate before calling
if reviewers.is_empty() { return Err(anyhow!("no reviewers given")); }
let pr = client.get_pull_request(owner, repo, pr_number).await?; // 404 check before mutation
for r in reviewers {
if !client.is_collaborator(owner, repo, r).await.unwrap_or(false) {
return Err(anyhow!("{r} is not a collaborator of {owner}/{repo}"));
}
} Type guard
fn is_ok_status(status: reqwest::StatusCode) -> bool { status.is_success() } Try / catch
match client.request_reviewers(owner, repo, pr, &reviewers).await {
Ok(()) => info!("reviewers requested"),
Err(e) if e.to_string().contains("422") => warn!("reviewer not requestable, skipping: {e}"),
Err(e) => return Err(e),
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed to create pull request comment
- Failed to delete comment
- Failed to update comment
- Failed to withdraw review request
- Anthropic API error ( )
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/faf54fa4c2b67e09.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-github/src/client.rs:886
owner: &str,
repo: &str,
pr_number: i64,
reviewers: &[String],
) -> Result<()> {
let url = format!(
"{}/repos/{}/{}/pulls/{}/requested_reviewers",
self.base_url, owner, repo, pr_number
);
let response = self
.client
.post(&url)
.json(&ReviewersBody { reviewers })
.send()
.await?;
if !response.status().is_success() {
bail!(
"Failed to request reviewers: {}",
response_error(response).await
);
}
Ok(())
}
pub async fn remove_requested_reviewers(
&self,
owner: &str,
repo: &str,
pr_number: i64,
reviewers: &[String],
) -> Result<()> {
let url = format!(
"{}/repos/{}/{}/pulls/{}/requested_reviewers",
self.base_url, owner, repo, pr_numberView on GitHub (pinned to 58e5313667)