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

  1. Reduce the number of open PRs (close or merge stale ones, e.g. automated dependency PRs).
  2. Narrow the query to a subset of PRs if the API supports filters (branch, label) so pagination stays within bounds.
  3. Increase `MAX_PAGES` if you maintain the code and genuinely need larger listings.
  4. 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

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


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)