Skip to content

[Bug]: PR views fail with a fine-grained GitHub token (check runs are unreadable) #15229

Closed

Description

@ClumsyAdmin

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. Create a fine-grained personal access token for a repository that runs GitHub Actions on pull requests. Give it read (or higher) on Pull requests, Contents, Issues, Actions, Workflows, Commit statuses, and Metadata.
  2. On the machine running the T3 Code server: gh auth login --with-token < token.txt
  3. Open a project for that repository in T3 Code, and open the pull request list or any pull request.

Expected behavior

Pull requests load. A token that can't read checks should still let T3 Code show the pull request without them.

Actual behavior

The pull request list and pull request detail fail completely. Plain gh commands with the same token work, for example gh pr checkout and gh pr list without check fields.

The pull request list and detail ask for check status in the same request as everything else:

  • The list uses gh pr list --json …,statusCheckRollup (PULL_REQUEST_LIST_JSON_FIELDS in apps/server/src/pullRequest/gitHubPullRequestJson.ts).
  • The detail uses pullRequestCoreGraphQlQuery, in the same file, which reads every check under statusCheckRollup.contexts.

On a repository that uses GitHub Actions, those checks are check runs. Reading check runs needs the Checks permission, which GitHub grants only to GitHub Apps. A fine-grained personal access token can't be given it. When one field is refused, gh exits non-zero and the whole read fails, so one unreadable optional field takes down the whole pull request view.

Adding Commit statuses: Read gets past the rollup itself, but each check run inside it is still refused. The REST checks endpoint returns 403 with the same token, so this comes from GitHub's permission model, not from gh.

The error also isn't recognised: classifyNonZeroExit (apps/server/src/vcs/VcsProcess.ts) reports it as a generic command failure, with no hint that the token type is the cause.

Impact

Major degradation or frequent failure

Version or commit

main @ ce90eec

Environment

T3 Code server on Debian, used remotely. gh from the official cli.github.com apt repository (reproduced both before and after upgrading from Debian's packaged gh). github.com.

Logs or stack traces

# Each field requested separately with `gh pr list --json number,<field>`:
PASS  pr list --json author / mergeable / reviewDecision / additions / reviewRequests / latestReviews / labels
PASS  graphql assignableUsers

# Without Commit statuses:
FAIL  pr list --json statusCheckRollup
      GraphQL: Resource not accessible by personal access token (repository.pullRequests.nodes.0.statusCheckRollup.nodes.0.commit.statusCheckRollup)

# With Commit statuses: Read added, each check run is still refused:
FAIL  pr list --json statusCheckRollup
      GraphQL: Resource not accessible by personal access token (repository.pullRequests.nodes.0.statusCheckRollup.nodes.0.commit.statusCheckRollup.contexts.nodes.0), … (one per check run)
FAIL  PR detail GraphQL query
      gh: Resource not accessible by personal access token

$ gh api repos/OWNER/REPO/commits/SHA/check-runs
{"message":"Resource not accessible by personal access token","documentation_url":"https://docs.github.com/rest/checks/runs#list-check-runs-for-a-git-reference","status":"403"}

Workaround

Sign gh in with gh auth login --web, or with a classic personal access token that has the repo scope. Both can read check runs.

Activity

  1. changed the title [-][Bug]: PR views and merge auto-settle fail with a fine-grained GitHub token (check runs are unreadable)[/-] [+][Bug]: PR views fail with a fine-grained GitHub token (check runs are unreadable)[/+] on Oct 3, 2026
  2. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks @ClumsyAdmin for the field-by-field breakdown. It made this easy to confirm. I checked it on main at ce90eec1ff, and no existing issue covers it.

    A fine-grained personal access token can't read check runs. GitHub doesn't offer a Checks permission for that token type, so GET /repos/{owner}/{repo}/commits/{sha}/check-runs returns 403 even when Commit statuses, Actions, and Workflows are readable. A classic token with the repo scope, or gh auth login --web, can read them. That part is GitHub's permission model, and your workaround is right.

    The T3 Code side is that it asks for those checks in the same gh call as the pull request itself. gh exits non-zero when any selected field is refused, and nothing retries without the checks. classifyNonZeroExit in apps/server/src/vcs/VcsProcess.ts doesn't recognize the message, so it shows up as a generic command failure.

    Where it fails

    • List: PULL_REQUEST_LIST_JSON_FIELDS in apps/server/src/pullRequest/gitHubPullRequestJson.ts includes statusCheckRollup, which matches your log: every other field passes, and statusCheckRollup fails once the head commit has check runs.
    • Detail: pullRequestCoreGraphQlQuery in the same file selects statusCheckRollup.contexts and each CheckRun (including checkSuite.workflowRun), so one refused check fails the read.
    • Pull request page: it tries a host search first (pullRequestSearchGraphQlQuery, which asks only for statusCheckRollup { state }). If that's refused, it falls back to gh pr list --json with the full rollup, which fails too, and the repository is reported as unreadable.
    • Merge auto-settle: ThreadSettlementService reads the linked pull request through summary with recoverTransientFailure: false. The batched summary asks for statusCheckRollup { state }, a GraphQL error drops the whole batch, and the per-PR fallback gh pr view --json uses PULL_REQUEST_DETAIL_JSON_FIELDS, which includes every check. Settlement only needs state and mergedAt, but never gets them, so a merged thread stays unsettled.

    A repository whose head commit has no check runs isn't affected.

    Likely fix area

    A maintainer will decide on the fix direction. One option is to treat checks as optional: when they can't be read, the list, detail, and settlement reads still succeed with check state shown as unknown, and the token-type error is recognized so the message points at the cause.

  3. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 3, 2026
  4. ScottN-PV commented on Oct 15, 2026

    @ScottN-PV
    Contributor

    #16171 closed for going over the 500-line limit, so here is a smaller fix to agree on first.

    From reading main 42da166d13: the list, pull request page and merge-settlement reads now ask only for the overall check state, so with Commit statuses: Read they no longer need check-run access. Opening a pull request still reads every check run, and GitHubApi fails the whole answer on any refusal, so the detail view fails whenever the token cannot read the head's check runs. I have not rerun this SHA with a fine-grained token; #16171's earlier token run saw the same split.

    Two options:
    A. When the detail read is refused only for checks, read it again without them and show checks as unavailable (not "No checks reported") on web and mobile. About 80–200 non-test lines, under 400 with tests.
    B. Keep the failure, but add a line to the existing error saying the server's token cannot read check runs. About 20–30 non-test lines.

    We prefer A. Would you take A, or B first?

    Note

    Comment drafted by Claude Fable 5.1 on behalf of @ScottN-PV.

  5. t3dotgg commented on Oct 21, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Thanks for the report. One part of this is fixed on main in #16320 and #19224. Please test on the nightly built from main on 2026-10-21, or on the next stable release. One part is still open: Opening PR detail can still fail when the token cannot read check runs. If that part still matters to you, please open a new issue for that part only.

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.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions