gitbutlerapp/gitbutler · error
Open pull request listing exceeded
Error message
Open pull request listing exceeded {MAX_PAGES} pages What it means
`list_open_pulls` pages through GitHub's PR listing with `get_all_pages` fetching up to `MAX_PAGES + 1` pages of 100 items; `anyhow::ensure!` fails with this message when the accumulated result reaches the full `(MAX_PAGES + 1) * 100` size, meaning more pages likely exist than the hard safety bound allows. It prevents unbounded memory growth and runaway pagination on very large repositories.
Solutions
- Reduce the number of open PRs (close or merge stale ones, e.g. automated dependency PRs).
- Narrow the query to a subset of PRs if the API supports filters (branch, label) so pagination stays within bounds.
- Increase `MAX_PAGES` if you maintain the code and genuinely need larger listings.
- Use a targeted PR fetch by number instead of listing all open PRs.
Defensive patterns
Strategy: fallback
Validate before calling
// Before listing, cap work: skip listing when repo is known to exceed the bound // (e.g. track open-PR count from a prior run and refuse if >= MAX_PAGES * 100).
Try / catch
match client.list_open_pulls(owner, repo).await {
Ok(pulls) => pulls,
Err(e) if e.to_string().contains("exceeded") => {
eprintln!("Too many open PRs for a full listing; use a targeted fetch by number");
Vec::new()
}
Err(e) => return Err(e),
} Prevention
- Close/merge stale and automated PRs regularly to keep listings small
- Prefer fetching PRs by number over full open-PR listings
- Use branch/label filters to narrow listings where available
When it happens
Trigger: Listing open PRs on a repository with more than `MAX_PAGES * 100` open pull requests (each page holding 100 items).
Common situations: Very large monorepos or bots creating thousands of open PRs; a CI fleet that never closes PRs; repositories with thousands of stale automated dependency-update PRs.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Could not update all PR targets before native stack…
- Failed to get PR base repo
- Failed to update pull request
- GitHub GraphQL convertPullRequestToDraft returned an empty…
- GitHub GraphQL disablePullRequestAutoMerge returned an…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/481be2515832522d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-github/src/client.rs:302
/// Pages are fetched in ascending creation-time order so offset
/// pagination stays stable while the repository is active: updates never
/// move a PR and new PRs only append. A close or reopen racing the scan
/// can still shift a page boundary, duplicating a boundary PR (the
/// freshest copy is kept) or omitting one (a later refresh restores it,
/// though the review cache may briefly drop its row in between).
pub async fn list_open_pulls(&self, owner: &str, repo: &str) -> Result<Vec<PullRequest>> {
const MAX_PAGES: usize = 100;
let url = format!(
"{}/repos/{}/{}/pulls?state=open&sort=created&direction=asc",
self.base_url, owner, repo
);
let pulls = self
.get_all_pages::<GitHubPullRequest>(&url, MAX_PAGES + 1)
.await?;
// Every fetched page being full means the listing may extend past
// what was fetched; a short final page is complete however far past
// the nominal bound it runs.
anyhow::ensure!(
pulls.len() < (MAX_PAGES + 1) * 100,
"Open pull request listing exceeded {MAX_PAGES} pages"
);
// Later duplicates overwrite earlier ones, keeping the freshest copy.
let pulls: std::collections::BTreeMap<_, _> =
pulls.into_iter().map(|pull| (pull.number, pull)).collect();
let mut pulls = pulls.into_values().collect::<Vec<_>>();
// RFC 3339 timestamps compare chronologically as strings; consumers
// that pick one PR per branch rely on the freshest coming first.
pulls.sort_by(|a, b| b.updated_at.cmp(&a.updated_at));
Ok(pulls.into_iter().map(Into::into).collect())
}
/// List the PRs for a given target.
pub async fn list_pulls_for_base(
&self,
owner: &str,
repo: &str,View on GitHub (pinned to 58e5313667)