fix: normalize extension-provided CancellationToken in _findFilesBase (fixes #318999)#319018
Merged
vs-code-engineering[bot] merged 2 commits intoMay 29, 2026
Conversation
…fixes #318999) Extensions that bundle their own CancellationToken module produce tokens that fail the RPC protocol's instanceof check in isCancellationToken(). When this happens, the token is serialized over the wire as a plain object (without functions/getters), causing 'onCancellationRequested is not a function' on the main thread. Fix by validating the token before passing it to the RPC proxy. If it fails isCancellationToken(), create a linked CancellationTokenSource with a properly recognized token. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
roblourens
approved these changes
May 29, 2026
rzhao271
approved these changes
May 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Error:
TypeError: i.onCancellationRequested is not a functioninraceCancellationErrorwhen theSearchService.doSearchmethod passes an invalid token toraceCancellationError.Root Cause: Extensions that bundle their own
CancellationTokenmodule (e.g., GitHub Copilot Chat) create tokens from a separateMutableTokenclass. These tokens fail theinstanceof MutableTokencheck in the RPC protocol'sisCancellationToken(). While they normally pass the duck-type fallback check, under certain bundling/runtime conditions the token is not recognized, causing it to be serialized over the wire as a plain object. Since functions and getters don't survive serialization, the main thread receives{ _isCancelled: false, _emitter: null }— truthy but withoutonCancellationRequested.Fixes #318999
Recommended reviewer:
@roblourensCulprit Commit
Most likely
b02737df(May 14, 2026) by@osortega— "Add experimental opt-in to honor .gitignore in findFiles extension API (#316349)". This commit restructured_findFilesImpland extracted_findFilesBase, creating the code path where extension-provided tokens are passed directly to the RPC proxy without validation.Code Flow
sequenceDiagram participant Ext as Copilot Extension participant EH as ExtHostWorkspace participant RPC as RPC Protocol participant MT as MainThreadWorkspace participant SS as SearchService Ext->>EH: findFiles2(patterns, opts, bundledToken) EH->>EH: _findFilesImpl -> _findFilesBase(queryOptions, token) EH->>RPC: proxy.$startFileSearch(folder, options, bundledToken) Note over RPC: isCancellationToken(bundledToken) fails RPC->>RPC: Serializes token as plain object RPC->>MT: $startFileSearch(folder, options, brokenToken) MT->>SS: fileSearch(query, brokenToken) SS->>SS: doSearch -> raceCancellationError(promise, brokenToken) Note over SS: brokenToken.onCancellationRequested is undefined SS-->>SS: TypeError thrownAffected Files
src/vs/workbench/api/common/extHostWorkspace.tssrc/vs/workbench/services/search/common/searchService.tsraceCancellationError(promise, token)src/vs/base/common/async.tstoken.onCancellationRequested()src/vs/workbench/api/browser/mainThreadWorkspace.tsRepro Steps
CancellationTokenSourcecreates a tokenisCancellationToken()in the RPC layeronCancellationRequestedSearchService.doSearchcrashes when callingraceCancellationErrorHow the Fix Works
Chosen approach (
src/vs/workbench/api/common/extHostWorkspace.ts):Added a validation guard in
_findFilesBasethat checks if the incoming token is recognized byCancellationToken.isCancellationToken()before passing it to the RPC proxy. If the token is not recognized (fails the instanceof and duck-type checks), a newCancellationTokenSourceis created and linked to the original token'sonCancellationRequestedevent. The linked token — which IS recognized by the RPC — is used instead. This fixes the problem at the data producer boundary (where the unrecognized token enters the RPC layer), not at the crash site.Alternatives considered:
mainThreadWorkspace.$startFileSearchto validate the received token — this would be fixing at the crash site rather than preventing bad data from being produced.raceCancellationErrorto handle missingonCancellationRequested— this silences the error instead of fixing the cause.Recommended Owner
@roblourens— owns the search/workspace extension API area where the fix is applied.