Skip to content

fix: handle 'no choices' response gracefully in xtab fetch stream (fixes #318235)#318236

Open
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/xtab-no-choices-unhandled-error-56d2530e65ee52a8
Open

fix: handle 'no choices' response gracefully in xtab fetch stream (fixes #318235)#318236
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/xtab-no-choices-unhandled-error-56d2530e65ee52a8

Conversation

@vs-code-engineering
Copy link
Copy Markdown
Contributor

Summary

The GitHub.copilot-chat extension's xtab provider (Next Edit Suggestions) was surfacing an unhandlederror in telemetry when the model returned a "Response contained no choices" response. The error is benign — it means the model had no edit to suggest — but was being wrapped in ErrorUtils.fromUnknown() and used to reject a fetch stream that was never consumed, causing an unhandled promise rejection. This affects ~9,400 users across versions 0.48.0 and 0.49.0 on Windows.

Fixes #318235
Recommended reviewer: @ulugbekna

Culprit Commit

This is a pre-existing issue — the error bucket has hits in both extension version 0.48.0 (first seen 2026-05-12) and 0.49.0 (first seen 2026-05-19). The code pattern has been present since the fetch stream architecture was introduced. No single culprit commit introduced this regression.

Code Flow

sequenceDiagram
    participant Model as LLM Model
    participant Fetch as fetchResultPromise
    participant ThenHandler as .then() handler (L823)
    participant RaceHandler as Promise.race (L846)
    participant Stream as fetchStreamSource

    Model->>Fetch: Response (type=Unknown, reason="no choices")
    Fetch->>ThenHandler: resolves
    Fetch->>RaceHandler: resolves
    ThenHandler->>Stream: reject(FetchStreamError(ErrorUtils.fromUnknown(...)))
    Note over ThenHandler: Creates Error with full JSON payload
    RaceHandler->>RaceHandler: L855 check passes, returns NoSuggestions early
    Note over Stream: Stream rejected but never consumed
    Note over Stream: Unhandled rejection surfaces in telemetry
Loading

Affected Files

File Role Evidence
extensions/copilot/src/extension/xtab/node/xtabProvider.ts crash site + fix location L826: fetchStreamSource.reject(new FetchStreamError(mapChatFetcherErrorToNoNextEditReason(response)))
extensions/copilot/src/util/common/errors.ts error construction L19: new Error(\An unexpected error occurred: ${safeStringify(error)}`)`

Repro Steps

  1. Open a file in VS Code with Copilot enabled and NES (Next Edit Suggestions) active
  2. Trigger an inline edit suggestion where the model returns no choices (e.g., when there are no meaningful edits to suggest)
  3. The model responds with {type: "unknown", reason: "Response contained no choices."}
  4. The error surfaces as an unhandled rejection in telemetry

This is non-deterministic — it depends on the model deciding it has no edits to suggest.

How the Fix Works

Chosen approach (extensions/copilot/src/extension/xtab/node/xtabProvider.ts):

Added a check for RESPONSE_CONTAINED_NO_CHOICES in the .then() handler at line 825, mirroring the existing check at line 855. When the response is type Unknown with reason "Response contained no choices", the stream is resolved (not rejected with an error) because this is an expected outcome — the model simply has no edit to suggest. The main code path at line 855 already handles this case gracefully by returning NoSuggestions, so the stream will never be consumed anyway. Fix at the data producer (the .then() handler that creates the error), not the crash site (the unhandled rejection handler).

Alternatives considered: Wrapping the stream consumption in try/catch would hide the error without fixing the data producer — rejected.

Recommended Owner

@ulugbekna — owns NES (Next Edit Suggestions) extension side per working-areas.md. Active in the last 90 days (commits as recent as 2026-05-23).

Generated by errors-fix · ● 62.7M ·

 #318235)

The .then() handler on fetchResultPromise was rejecting the fetch stream
with an error for the 'Response contained no choices' case, even though
this is an expected outcome handled gracefully at line 855. When the
Promise.race resolved with the fetchResult directly, the stream rejection
went unhandled, surfacing as an unhandlederror in telemetry.

Add the same RESPONSE_CONTAINED_NO_CHOICES check that exists at line 855
into the .then() handler, resolving the stream instead of rejecting it
with an error for this expected case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 25, 2026 16:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 May 25, 2026 16:28
@vs-code-engineering vs-code-engineering Bot enabled auto-merge (squash) May 25, 2026 16:28
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] [GitHub.copilot-chat] unhandlederror-An unexpected error occurred: {"type":"unknown","reason":"Response contained no choic...

2 participants