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

  1. Read the embedded GitHub error body in the message to see the exact status and reason.
  2. Verify the token has write access on pull requests for the repository (classic: `repo` scope; fine-grained: Pull requests: Read and write).
  3. Confirm the reviewers are collaborators or previously commented on the PR; otherwise add them first or use the correct login.
  4. Check owner/repo/pr_number resolve to an existing PR (`GET /repos/{owner}/{repo}/pulls/{n}`).
  5. 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

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


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_number

View on GitHub (pinned to 58e5313667)