Skip to content

[Bug]: PR sync reads pull requests GitHub cannot find on every sweep, even on settled threads #17799

Closed

Description

@abiassi

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Link a pull request URL for which GitHub already returns NOT_FOUND when using the server's credential. The repository can be deleted, or private and inaccessible to the server's GitHub credential. My links point to private repositories that my credential cannot access. The link never gets a snapshot.
  2. Settle the thread.
  3. Leave the server running. No client needs to be open.
  4. Count the getPullRequestSummary spans under PullRequestSyncReactor.sweep in server.trace.ndjson.

The access failure itself may be expected. The bug is that the sync retries the failed read every minute indefinitely, even on settled threads.

Expected behavior

Settled threads do not trigger periodic reads of their linked pull requests. The user guide says "A settled thread's reviews stop refreshing until you unsettle it." On unsettled threads, the sync retries pull requests that GitHub cannot find every 15 minutes, like closed pull requests.

Actual behavior

The sync reads each of these pull requests on every one-minute sweep indefinitely, including those on settled threads. On my machine, 9 such links, all on settled threads, made 10 failed GraphQL requests a minute: one failed batch and 9 single reads. In my current trace files, 52 sweeps made 10 failed reads each. All 520 reads failed. These failed reads accounted for 520 of the 538 GraphQL requests the server sent during that time. My earlier measurement, with 38 such links across about 150 threads, counted 1,240 failed reads in 36 minutes. The account ran out of GraphQL quota, and other gh commands that use GraphQL failed until the reset.

Three paths in apps/server/src/orchestration-v2/PullRequestSyncReactor.ts keep these links due:

  1. isDue returns true for any link without a snapshot before it filters out settled threads. fix(server): settled threads stop polling their pull requests #16762 left this check above the settled filter.
  2. syncGroup clears a requested key only after a successful read. After a not-found read, the key stays requested. Every later sweep reads the pull request again, even if the thread is settled.
  3. Each thread.pull-request-synced event requests every link on the thread that has no snapshot. A sync of any other link on that thread requests the unreadable ones again.

The GitHub batch fallback adds to the cost. One NOT_FOUND alias causes the whole batched summary query to fail. GitHubPullRequestApi then reads each pull request in that batch separately, including readable ones.

I have a fix that changes only the reactor and includes regression tests. It applies the no-snapshot rule only to unsettled threads. The fix treats a not-found answer as a finished read and clears the request. On unsettled threads, periodic sweeps retry the pull request every 15 minutes. Another link's sync no longer requests the missing pull request again. A reader's refresh still does. A PR with this fix follows this issue.

The reactor's polling logic is the same on main at c77a7b7. A dev server on main with a copy of my data makes the same 10 failed requests per sweep.

Related:

Investigated and filed with Claude Code (Claude Opus 5.5).

Impact

Major degradation or frequent failure

Version or commit

0.0.46-nightly.20261008.2833

Environment

macOS 27.0, T3 Code (Nightly) desktop app, GitHub through the app's GitHub API transport.

Logs or stack traces

# Summary reads under PullRequestSyncReactor.sweep, from server.trace.ndjson
sweep 10:41  GitHubApiNotFoundError  10
sweep 10:42  GitHubApiNotFoundError  10
sweep 10:43  GitHubApiNotFoundError  10
# 52 of the 53 sweeps from 08:56 to 10:43 UTC made 10 failed reads each: 520 reads, 0 successes.

WARN pull request sync skipped
  { count: 9, reason: 'Pull request operation summary failed: GitHub could not find the requested resource, or the credential cannot see it.' }

Screenshots, recordings, or supporting files

No response

Workaround

Unlink the unreadable pull requests, or archive their threads. The sweep skips unlinked pull requests and archived threads.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Oct 10, 2026
  2. aram-eskandari commented on Oct 19, 2026

    @aram-eskandari

    Same issue here on T3 Code (Beta) 0.1.0, macOS, on a much larger scale.

    Setup: three github.com accounts logged into gh. Threads had PRs linked from repos owned by the two non-active accounts, which the active credential can't see (also #14123). 112 links across ~25 threads (open, settled and older ones) never got a snapshot.

    What I measured (server.trace.ndjson, 30-minute window):

    • 4,489 getPullRequestSummary GraphQL calls, all under PullRequestSyncReactor.sweep → syncGroup → PullRequestService.persistedRead → PullRequestReadCache.get
    • ~180 calls/min (~10,800/h), more than twice the 5,000/h budget, so the quota ran out about 30 minutes after each reset
    • nearly every read failed with GitHub could not find the requested resource, or the credential cannot see it
    • gh and everything else on the same account then hit API rate limit exceeded for GraphQL

    Workaround: unlinking the 112 links (via the unlink_pull_request MCP tool, passing threadId) took it from ~185 calls/min to 0–2 calls/min within two minutes.

    They come back whenever an agent links a new PR in one of those repos, so it would help to remember NOT_FOUND results per link with a long backoff, as the issue suggests, or to pick the credential per repo owner (#14123).

  3. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Reproduced on Linux with the web dev server at 70e5e384da. Linked a nonexistent GitHub pull request, received GitHubApiNotFoundError, then settled its thread. The reactor retried at 22:52, 22:53, and 22:54 UTC; the last attempt occurred after closing the browser.

    Runtime transcript. Regression tests also reproduce the settled-thread retries, missing-result backoff, and sibling re-request paths.

  4. PolarBearEs commented on Oct 30, 2026

    @PolarBearEs

    Same on Bitbucket Cloud (0.1.6-nightly.20261030.3917, Linux).

    I had 12 linked Bitbucket pull requests, 11 of them on settled threads, and none had a snapshot. Every one-minute sweep reread all 12: isDue returns true for a missing snapshot before it checks whether the thread is settled. The reads failed with 404 first, then 429.

    Each Bitbucket read is 5 requests (#27578), so that came to about 3,600 requests an hour, against Bitbucket's limit of 1,000. The host stayed paused, and while it was paused I couldn't open pull requests either (#27579). Unlinking the pull requests stopped it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions