gitbutlerapp/gitbutler · error · anyhow::Error
Failed to list GitHub stacks: {}
Error message
Failed to list GitHub stacks: {} What it means
GET /repos/{o}/{r}/stacks?pull_request=N returned a non-2xx status. A 404 is already translated internally to Ok(None) (stacks not present/unsupported), so this message means a genuine failure: authentication, permissions, rate limiting, or a server fault on the Stacks endpoint.
Source
Thrown at crates/but-github/src/stacks.rs:292
impl GitHubClient {
/// `Ok(None)` means the repository does not expose the native stacks endpoint.
async fn stacks_for_pull_request(
&self,
owner: &str,
repo: &str,
review_number: i64,
) -> Result<Option<Vec<Stack>>> {
let response = self
.client
.get(format!("{}/repos/{owner}/{repo}/stacks", self.base_url))
.query(&[("pull_request", review_number)])
.send()
.await?;
if response.status() == reqwest::StatusCode::NOT_FOUND {
return Ok(None);
}
if !response.status().is_success() {
bail!(
"Failed to list GitHub stacks: {}",
response_error(response).await
);
}
Ok(Some(response.json().await?))
}
async fn create_stack(&self, owner: &str, repo: &str, desired: &[i64]) -> Result<()> {
let response = self
.client
.post(format!("{}/repos/{owner}/{repo}/stacks", self.base_url))
.json(&StackMembersBody {
pull_requests: desired,
})
.send()
.await?;
if !response.status().is_success() {
bail!(View on GitHub (pinned to caf1f223d3)
Solutions
- Read the wrapped status and body - 401/403 means re-authenticate or fix permissions, 429 means back off
- Confirm the account can read the repository
- Retry once with backoff for transient failures
Defensive patterns
Strategy: try-catch
Try / catch
match client.list_stacks(owner, repo, pr_number).await {
Ok(stacks) => stacks,
Err(e) if e.to_string().starts_with("Failed to list GitHub stacks") => {
log::warn!("stacks listing failed (possibly unsupported/rate-limited): {e}");
None // degrade gracefully: stacks are optional metadata
}
other => other?,
} Prevention
- Treat 404 as 'no stacks' (the client already does) and other failures as transient first
- Rate-limit stack queries in polling loops
- Verify the account can read the repo before stack operations
When it happens
Trigger: Token lacks read access to the repo; primary or secondary rate limits; GitHub Stacks feature-rollout gaps; GitHub Enterprise instances without the stacks endpoint answering 5xx.
Common situations: Beta API surface behind flags; heavy automation hitting rate limits; enterprise proxies in front of the API.
Related errors
- Failed to create GitHub stack: {}
- Failed to add to GitHub stack: {}
- Failed to unstack GitHub stack: {}
- Could not restore all review targets after the push failed:
- GitHub GraphQL enablePullRequestAutoMerge returned an empty
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/0594efebdd3d48d3.
Report an issue: GitHub.