Skip to content

fix: don't cache rejected oniguruma WASM load promise (fixes #326825) - #326830

Merged
vs-code-engineering[bot] merged 2 commits into
mainfrom
fix/oniguruma-wasm-cache-326825-2f5e6649688551bf
Aug 23, 2026
Merged

fix: don't cache rejected oniguruma WASM load promise (fixes #326825)#326830
vs-code-engineering[bot] merged 2 commits into
mainfrom
fix/oniguruma-wasm-cache-326825-2f5e6649688551bf

Conversation

@vs-code-engineering

Copy link
Copy Markdown
Contributor

Summary

TypeError: Failed to fetch is thrown from TextMateTokenizationFeature._loadVSCodeOnigurumaWASM when the renderer fetches the local onig.wasm asset (e.g. while editors are being restored during window startup/teardown). The fetch itself is a transient/environmental failure, but the memoization in _getVSCodeOniguruma caches the rejected promise permanently: this._vscodeOniguruma is assigned the rejecting async IIFE and never reset on failure. As a result, a single transient blip poisons TextMate tokenization for the entire session — every subsequent language whose tokenizer is created re-awaits the same rejected promise, and each one re-reports the error through onUnexpectedError. This amplification explains the hits-per-user ratio (218 hits / 125 users in 1.129.1) and why the bucket appears in essentially every shipped version.

The fix stops the amplification: on failure we clear the cache so a later request can retry, while still re-throwing so the genuine failure is reported once (never silenced).

Fixes #326825
Recommended reviewer: @alexdima

Culprit Commit

Not identified via git blame — the workspace is a shallow (fetch-depth=1) clone, so line history is unavailable. The memoization pattern is long-standing; the bucket history shows hits across every tracked version (1.110 → 1.129), so this is not a single-commit regression but a long-lived latent amplifier. The recent feat: restore asar for node_modules (#324897) change altered the built onig.wasm resource path (node_modules.asar.unpacked/...) and is a plausible contributor to the recent uptick in transient fetch failures, but it is not the root cause of the telemetry amplification.

Code Flow

flowchart TD
    A[LanguageService.requestRichLanguageFeatures] --> B[TokenizationRegistry.getOrCreate]
    B --> C[factory.resolve -> _create]
    C --> D[TextMateTokenizationFeature.createSupport]
    D --> E[_createTokenizationSupport try/catch]
    E --> F[_getOrCreateGrammarFactory]
    F --> G[_getVSCodeOniguruma - memoized]
    G --> H[_loadVSCodeOnigurumaWASM: fetch onig.wasm]
    H -- Failed to fetch --> I[rejected promise cached in _vscodeOniguruma]
    I -- reused by every later language --> G
    E -- catch --> J[onUnexpectedError -> telemetry, once per language]
Loading

Affected Files

  • src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts_getVSCodeOniguruma() memoization now clears the cached promise on failure.

Repro Steps

  1. Open a workspace so editors are restored on startup (multiple files of different languages).
  2. Cause the onig.wasm fetch to fail transiently (network hiccup, resource unavailable during window teardown/reload, or a slow/aborted request while the window is closing).
  3. Observe that once the first fetch fails, TextMate tokenization stays broken for the whole session and Failed to fetch is reported repeatedly (once per language whose tokenizer is requested), rather than a single transient report followed by recovery.

How the Fix Works

Chosen approach (textMateTokenizationFeatureImpl.ts, _getVSCodeOniguruma): wrap the memoized async loader in a try/catch that, on failure, resets this._vscodeOniguruma = null before re-throwing. This fixes the defect at the data producer — the memoization cache is where the permanently-broken state is created — rather than at the crash site (_loadVSCodeOnigurumaWASM). The catch does not silence anything: it re-throws so _createTokenizationSupport's existing catch still routes the genuine failure to onUnexpectedError exactly once, preserving the telemetry pipeline. After this change a transient Failed to fetch no longer poisons the whole session; the next tokenizer request re-attempts the load and can succeed.

Alternatives considered:

  • Swallowing the error in _createTokenizationSupport's catch (e.g. treating Failed to fetch like the benign missing-grammar case): rejected because it hides a real failure from telemetry instead of fixing the state-caching defect that causes the repeated reports.
  • Adding a guard/try-catch at the crash site in _loadVSCodeOnigurumaWASM: rejected because it masks the symptom at the bottom of the stack and does not address the cache poisoning that produces the amplification.

Recommended Owner

@alexdima — owns the editor tokenization / TextMate service area (src/vs/workbench/services/textMate, src/vs/editor/common/tokenizationRegistry.ts).

Generated by errors-fix · 1.8K AIC · ⌖ 34.9 AIC · ⊞ 71K ·

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 21, 2026 15:53

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.

Pull request overview

Note

Copilot could not run the full agentic suite for this review because it was automatically requested on a bot-authored pull request. Request a review from Copilot under Reviewers to retry with the full agentic suite. Improved support for bot-authored pull requests is coming soon.

Prevents TextMate tokenization from becoming permanently broken for a session when vscode-oniguruma WASM loading fails transiently by avoiding caching a rejected initialization promise.

Changes:

  • Wrap vscode-oniguruma import + WASM load in a try/catch.
  • Reset _vscodeOniguruma to null on failure so later calls can retry initialization.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts:394

  • This four-line inline comment exceeds the repository's hard limit of one line for comments inside method bodies. Keep only the non-obvious cache rationale in a single line.
					// Do not cache a rejected promise: loading the WASM can fail with a transient
					// error (e.g. "Failed to fetch" while the window is being torn down). Caching
					// the rejection would permanently break tokenization for the rest of the
					// session and cause the same error to be re-reported for every language.

@vs-code-engineering
vs-code-engineering Bot merged commit 5c7bf1f into main Aug 23, 2026
28 checks passed
@vs-code-engineering
vs-code-engineering Bot deleted the fix/oniguruma-wasm-cache-326825-2f5e6649688551bf branch August 23, 2026 05:59
@vs-code-engineering vs-code-engineering Bot added this to the 1.135.0 milestone Aug 23, 2026
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-Failed to fetch

4 participants