Skip to content

fix: prevent expected Copilot auth error from leaking as unhandled rejection (fixes #321950)#321956

Open
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix-copilot-auth-unhandled-rejection-4cf83e42330ef5ca
Open

fix: prevent expected Copilot auth error from leaking as unhandled rejection (fixes #321950)#321956
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix-copilot-auth-unhandled-rejection-4cf83e42330ef5ca

Conversation

@vs-code-engineering

Copy link
Copy Markdown
Contributor

Summary

When createSession is invoked while the user is not authenticated, the agent host rejects with a by-design ProtocolError(AHP_AUTH_REQUIRED) ("Authentication is required to use Copilot"). That rejection is already handled by the awaiting caller and logged server-side, but AgentSubscriptionManager.trackSessionCreate also observes the same promise via void promise.finally(...). Promise.prototype.finally re-raises the settled rejection, and because the cleanup chain has no catch, the expected error is reported a second time as a renderer unhandled rejection — which is what telemetry buckets as unhandlederror-Authentication is required to use Copilot. The .code that would normally let BaseErrorTelemetry filter a ProtocolError is stripped during IPC serialization, so the re-wrapped error slips through the filter.

Fixes #321950
Recommended reviewer: @dmitrivMS

Culprit Commit

Field Value
Commit 5024d718
Author @dmitrivMS
PR #321526
Message Fix race condition involving eager createSession in chat sessions provider
Why This PR introduced the _inflightCreates / trackSessionCreate machinery (to make a subscribe wait for an in-flight create). The new void promise.finally(...) cleanup branch observes the create promise without a catch, so a rejected create now leaks an unhandled rejection. The bucket first appeared 2026-06-17, one day after this commit landed (2026-06-16), and is confined to 1.126.0-insider.

Code Flow

sequenceDiagram
    participant Caller as Renderer caller
    participant Local as localAgentHostService.createSession
    participant Track as AgentSubscriptionManager.trackSessionCreate
    participant Host as agent host (copilotAgent._ensureClient)
    participant Tel as Renderer ErrorTelemetry

    Caller->>Local: createSession(config)
    Local->>Host: _proxy.createSession(config) [RPC]
    Note over Host: Crash site (by-design):<br/>throw ProtocolError(AHP_AUTH_REQUIRED)<br/>when unauthenticated — logged via logService.error
    Host-->>Local: rejected promise (.code stripped by IPC serialization)
    Local->>Track: trackSessionCreate(uri, promise)
    Note over Track: ⚠️ Root cause:<br/>void promise.finally(cleanup) re-raises<br/>the rejection with no catch handler
    Track-->>Tel: unhandled rejection
    Note over Tel: reported as "UnhandledError -<br/>Authentication is required to use Copilot"
    Local-->>Caller: rejected promise (properly handled/awaited by caller)
Loading

Affected Files

  • src/vs/platform/agentHost/common/state/agentSubscription.tsfixed. trackSessionCreate (the producer of the spurious unhandled rejection).
  • src/vs/platform/agentHost/electron-browser/localAgentHostService.ts — context only (not changed). createSession registers the same promise with trackSessionCreate and also returns it to the caller; the dual reference is what lets the observation branch leak while the caller still handles the error.
  • src/vs/platform/agentHost/node/copilot/copilotAgent.ts — context only (not changed). _ensureClient throws ProtocolError(AHP_AUTH_REQUIRED); this is the legitimate, by-design crash site and is intentionally left untouched.

Repro Steps

  1. Run an Insiders build where Copilot is not yet authenticated (no GitHub token available to the agent host).
  2. Trigger a path that eagerly calls localAgentHostService.createSession(config) for a pre-specified session URI (e.g. restoring/opening a chat session before sign-in completes).
  3. The agent host's _ensureClient throws ProtocolError(AHP_AUTH_REQUIRED); the create promise rejects.
  4. Observe a renderer unhandled rejection reported to telemetry as unhandlederror-Authentication is required to use Copilot, even though the awaiting caller handled the rejection and the server logged it.

How the Fix Works

Chosen approach (src/vs/platform/agentHost/common/state/agentSubscription.ts, bypass site agentSubscription.ts:790): append a trailing no-op .catch(() => { }) to the void promise.finally(...) cleanup chain in trackSessionCreate. Promise.prototype.finally passes the original rejection through, so the cleanup chain — whose only job is to evict the _inflightCreates map entry — re-raised the rejection as an unhandled rejection on a pure observation branch.

This is the data-producer fix, not a crash-site fix: the change is applied exactly where the spurious unhandled rejection is produced. The real createSession rejection remains owned and handled by the awaiting caller and is still logged server-side via logService.error, so the no-op catch suppresses only the duplicate observation, not the real error — no error is hidden from logs or telemetry. This mirrors an existing deliberate swallow in the same class (getSubscription, lines 830–834), which already discards this same promise's rejection because the failure surfaces consistently via setError().

Alternatives considered:

  • Guard or try/catch at the crash site in copilotAgent._ensureClient — rejected: AHP_AUTH_REQUIRED is a by-design, client-handleable protocol error (code -32007); the throw and its logService.error are correct and must stay, and suppressing there would hide a legitimate error from the telemetry pipeline.
  • Wrap the createSession call/return in try/catch — rejected: that swallows an error the caller legitimately needs, hiding the symptom instead of fixing the producer of the unhandled rejection.
  • Restructure to .then(cleanup, cleanup) — equivalent runtime behavior, but it duplicates the cleanup callback and changes more lines; the trailing catch is the more minimal, intent-preserving edit.

Recommended Owner

@dmitrivMS — author of the culprit commit/PR #321526, which introduced trackSessionCreate.

  • Liveness gate: PASS — active in the last 90 days (commit 5024d718 on 2026-06-16, two days before the checked-out HEAD of 2026-06-18).
  • Team-membership gate: PASS (inferred) — landed merged PR Fix race condition involving eager createSession in chat sessions pro… #321526 directly into the core src/vs/platform/agentHost/** path (not a vendored extensions/** path) via GitHub's merge flow, indicating write access. The agent's gh is unauthenticated and no single-user-permission MCP tool is available, so the collaborators endpoint could not be queried directly; membership is inferred from the merged core-platform PR.

The issue is currently triage-assigned to bryanchen-d (error-fix driver); @dmitrivMS is the code owner for the introduced logic.

Generated by errors-fix · 4.2K AIC · ⌖ 213.5 AIC · ⊞ 69.3K ·

…jection (fixes #321950)

trackSessionCreate observed the createSession promise via `void
promise.finally(...)`. Promise.finally re-raises the settled rejection, so
when createSession rejected with a by-design error (e.g. AHP_AUTH_REQUIRED
when unauthenticated) the cleanup chain surfaced a duplicate unhandled
rejection on the renderer, even though the real caller and the server-side
logService.error already handle the error. Add a trailing no-op catch on the
observation branch so the inflight-map cleanup never participates in
unhandled-rejection telemetry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 18, 2026 16:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@vs-code-engineering vs-code-engineering Bot marked this pull request as ready for review June 18, 2026 16:25
@vs-code-engineering vs-code-engineering Bot enabled auto-merge (squash) June 18, 2026 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Error] unhandlederror-Authentication is required to use Copilot

2 participants