fix(github-issues): batch repo queries to avoid GitHub resource limits#9776
fix(github-issues): batch repo queries to avoid GitHub resource limits#9776PadreSVK wants to merge 3 commits into
Conversation
The card queried every repository owned by a Group/User in a single GraphQL request. For owners with many repositories this exceeded GitHub's per-request resource limit, so GitHub returned RESOURCE_LIMITS_EXCEEDED errors with null issue nodes, and the card crashed with "Cannot read properties of null (reading 'updatedAt')". - Fetch repositories in batches of 5 per GraphQL request so a single query stays within GitHub's resource limit. - Trim the issues query to what the UI renders: request assignees with `first: 1` (only the first assignee is shown) and drop the unused `participants` field. Both were nested fields driving the failures. - Filter out null issue nodes from partial responses so a partial failure no longer crashes the card. - Add tests for the batching behaviour and null-node handling. Signed-off-by: Patrik Švikruha <patrik.svikruha.dev@gmail.com>
Changed Packages
|
There was a problem hiding this comment.
Pull request overview
This PR hardens the GitHub Issues card against GitHub GraphQL per-request resource limits by batching repository queries, trimming nested fields in the issues query, and defensively handling partial responses that can contain null issue nodes.
Changes:
- Split large repository sets into batched GraphQL requests and merge results to avoid
RESOURCE_LIMITS_EXCEEDEDfailures. - Reduce GraphQL query complexity by fetching only
assignees(first: 1)and removing the unusedparticipantsfield. - Filter out
nullissue nodes in both the API layer and UI to prevent crashes; add regression tests.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| workspaces/github/plugins/github-issues/src/components/GithubIssues/IssuesList/IssuesList.tsx | Adds a defensive filter to avoid sorting/rendering null issue nodes. |
| workspaces/github/plugins/github-issues/src/api/githubIssuesApi.ts | Implements repo batching, trims the GraphQL selection set, and sanitizes partial responses (drops null nodes). |
| workspaces/github/plugins/github-issues/src/api/githubIssuesApi.test.ts | Adds tests for batching behavior and for null-node handling in partial responses. |
| workspaces/github/.changeset/github-issues-null-nodes.md | Documents the patch change and the user-facing fix in the changeset. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const batchResults = await Promise.all( | ||
| batches.map(async batch => { | ||
| try { | ||
| return (await octokit.graphql( | ||
| createIssueByRepoQuery(batch, itemsPerRepo, { | ||
| filterBy, | ||
| orderBy, | ||
| }), | ||
| )) as IssuesByRepo; | ||
| } catch (e) { | ||
| errorApi.post( | ||
| new ForwardedError('GitHub Issues Plugin failure', e), | ||
| ); | ||
| // GitHub may still return partial data for the batch alongside the | ||
| // errors; keep whatever resolved successfully. | ||
| return (e.data ?? {}) as IssuesByRepo; | ||
| } | ||
| }), | ||
| ); |
…e requests and resource limits Signed-off-by: Patrik Švikruha <patrik.svikruha.dev@gmail.com>
…ixtures Address review feedback: - Cap concurrent batched GraphQL requests (MAX_CONCURRENT_QUERIES) so entities owning many repositories don't fire a large burst of parallel requests that could trip GitHub's secondary rate limits. - Drop the unused `participants` field from test fixtures so they match the trimmed query and Issue type. Signed-off-by: Patrik Švikruha <patrik.svikruha.dev@gmail.com>
awanlin
left a comment
There was a problem hiding this comment.
Thanks for this @PadreSVK, overall this looks good, just left two comments.
Side note: please don't just check everything in the PR template checklist, there's no screenshots but you have them marked as provided. That lists not only helps you but as a reviewer it helps me as well. 👍
| '@backstage-community/plugin-github-issues': patch | ||
| --- | ||
|
|
||
| Fixed the GitHub Issues card failing with `Cannot read properties of null (reading 'updatedAt')` / repeated "Resource limits for this query exceeded." errors on entities (typically groups) that own many repositories. |
There was a problem hiding this comment.
Remove everything below this, this gets rolled up in the changelog and should be short and concise.
| **Issues are sorted from the recently updated DESC order (the plugin might not render all issues from a single repo next to each other).** | ||
|
|
||
| > [!Note] | ||
| > When an Entity owns many repositories, the plugin fetches issues from GitHub in several smaller batched requests instead of a single large query. This keeps each request within GitHub's GraphQL [per-request resource limit](https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api) — a single query spanning many repositories would otherwise fail with `RESOURCE_LIMITS_EXCEEDED`. If GitHub still returns a partial response for a batch, the issues that were fetched successfully are shown and the rest are skipped, rather than failing the whole card. |
There was a problem hiding this comment.
This makes a lot of sense to me and you have an error message when this fails but I'd like to also see something on the card itself. Something like a subtle warning in the card footer ("X issues couldn't be loaded") using the difference between totalCount and actual rendered edges would make this more transparent.

Hey, I just made a Pull Request!
The card queried every repository owned by a Group/User in a single GraphQL request. For owners with many repositories this exceeded GitHub's per-request resource limit, so GitHub returned RESOURCE_LIMITS_EXCEEDED errors with null issue nodes, and the card crashed with "Cannot read properties of null (reading 'updatedAt')".
first: 1(only the first assignee is shown) and drop the unusedparticipantsfield. Both were nested fields driving the failures.✔️ Checklist
Signed-off-byline in the message. (more info)