microsoft / microsoft/vscode

Agents window does not recover PR detection after repository GitHub token returns 401

Open
#327,788 0 comments 0 reactions 0 assignees View on GitHub
agents-window
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

- Copilot Chat Extension Version: N/A (local Agent Host / Agents window integration)
- VS Code Version: Code - Insiders build from 2026-07-24; exact version was not included in the exported bundle
- OS Version: macOS
- Feature (e.g. agent/edit/ask mode): Agents window, local Agent Host session, pull request detection
- Selected model (e.g. GPT 4.1, Claude 3.7 Sonnet): GPT-5.6 Sol (not believed to affect the issue)
- Logs: Reproduced in an Export Agent Host Debug Logs bundle. The key error is `AgentHostOctoKit GET https://api.github.com/repos///pulls?... - 401 Bad credentials`, followed by `AgentHostGitStateService.attachSessionGitHubPullRequest Failed to find pull request`. The renderer continues to report `hasPullRequest: false`.

Steps to Reproduce:

1. Sign in to GitHub/Copilot in VS Code and open the Agents window.
2. Start or resume a local Agent Host session in a Git worktree on a non-default branch.
3. Allow the repository-scoped GitHub authentication session (`https://api.github.com/repos`, `repo` scope) to become stale or revoked while the general Copilot authentication remains usable.
4. Create a pull request for the session branch using `gh pr create`. This succeeds because `gh` uses its own credential store. In the observed case, the PR existed and exactly matched the session repository and branch.
5. Return to or reload the Agents window and resume the session.
6. Observe that the Changes view still reports `hasPullRequest: false`, and the Agent Host logs a `401 Bad credentials` on every PR lookup.
7. Sign out and back in through the Agents window.
8. Observe that PR lookup can continue returning `401`; the separate repository-scoped GitHub session remains stale.

## Description

The Agents window discovers the correct repository and branch, but fails to attach an existing pull request when its repository-scoped GitHub token is invalid. The failure becomes persistent: the UI continues to behave as though no PR exists, even though the PR was successfully created and is visible through `gh`/GitHub.

This is especially confusing because normal Copilot functionality can remain authenticated, and signing out/in through the Agents window does not necessarily replace the distinct `repo`-scoped token used for GitHub REST operations.

## Expected behavior

When GitHub rejects the repository token, Agent Host should obtain a fresh `repo`-scoped token and retry PR detection. The session should then expose the PR and update `hasPullRequest` / `hasOpenPullRequest` accordingly. Recovery must be bounded and must not repeatedly call GitHub or repeatedly prompt the user.

## Actual behavior

`AgentHostGitStateService.attachSessionGitHubPullRequest` catches the `401`, logs a warning, and returns. It does not invalidate the token, emit `auth/required`, or retain the session for retry. Subsequent session restores or turn completions reuse the same rejected token and repeat the failure.

## Root cause analysis

1. PR detection obtains a token from `AgentHostAuthenticationService` for the protected resource `https://api.github.com/repos` with the `repo` scope.
2. The token is accepted into the Agent Host token store based on the authentication provider accepting it; it is not validated against the GitHub REST API at that point.
3. `AgentHostOctoKitService.findPullRequestByHeadBranch` calls the correct `/pulls?head=:` endpoint, but GitHub returns `401 Bad credentials`.
4. The caller treats this like a generic lookup failure. It logs the error but does not mark the token as rejected or notify the client that authentication expired.
5. Client-side token deduplication can continue treating the same token as already forwarded. Signing out/in of Copilot can refresh the Copilot token while leaving the separate `repo`-scoped authentication session unchanged.
6. `gh pr create` succeeds independently because the GitHub CLI uses a separate credential store, explaining why the PR exists while VS Code cannot detect it.

## Proposed fix

- Surface typed GitHub API failures, including status and `Retry-After` information.
- On `401`, mark that exact repository token as rejected and stop issuing GitHub requests with it.
- Emit `auth/required` with reason `expired` for the repository resource.
- Resolve a replacement `repo`-scoped session for the same account and forward only a different token.
- Retain affected sessions and retry their PR lookup only after fresh authentication is accepted.
- Serialize recovery per resource, defer interactive sign-in until a window is focused, and share a prompt cooldown across the editor and Agents windows.
- Retry only transient transport/408/429/5xx failures, at most three attempts with exponential backoff. Never retry a known-bad token.
- If the provider returns the same rejected token or recovery remains unsuccessful, stop and show one actionable authentication error rather than looping.
- Bind each lookup to one GitHub endpoint snapshot so an Enterprise endpoint change cannot send an old host's token to a new host.

Contributor guide

Open the contributing guide

Research direction

Start with AgentHostGitStateService.attachSessionGitHubPullRequest and AgentHostOctoKitService.findPullRequestByHeadBranch, then trace token handling through AgentHostAuthenticationService. Reproduce the 401 using the exported Agent Host debug logs and verify that recovery obtains a different repository-scoped token, updates pull-request state, and avoids repeated requests or prompts.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, typescript
Domain
api, authentication, devtools
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.