Skip to content

Webview workers can no longer load webview resources after #311844 #315494

@yongsooim

Description

@yongsooim

Type: bug

Does this issue occur when all extensions are disabled?: Not applicable; the repro requires a minimal webview extension.

VS Code Version: reproduced on 1.119.x; likely introduced by #311844

Steps to Reproduce

  1. Create a minimal extension with the files below.
  2. Run the extension and execute Worker import repro: Open.
  3. The webview prints starting import..., then the dynamic import never
    resolves; the browser eventually surfaces
    TypeError: Failed to fetch dynamically imported module.

The same setup worked before the webview service worker started streaming
resource responses through #311844.

Minimal repro:

{
  "activationEvents": ["onCommand:workerImportRepro.open"],
  "contributes": {
    "commands": [
      {
        "command": "workerImportRepro.open",
        "title": "Worker import repro: Open"
      }
    ]
  }
}
// extension.ts
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(vscode.commands.registerCommand('workerImportRepro.open', () => {
    const panel = vscode.window.createWebviewPanel(
      'workerImportRepro',
      'Worker import repro',
      vscode.ViewColumn.One,
      {
        enableScripts: true,
        localResourceRoots: [context.extensionUri],
      },
    );

    const workerModuleUri = panel.webview.asWebviewUri(
      vscode.Uri.joinPath(context.extensionUri, 'media', 'worker-module.js'),
    );

    panel.webview.html = /* html */ `<!DOCTYPE html>
      <html>
        <body>
          <pre id="log">starting import...</pre>
          <script>
            const log = document.getElementById('log');
            const source = \`
              import(${JSON.stringify(String(workerModuleUri))})
                .then(() => self.postMessage('import ok'))
                .catch(error => self.postMessage('import failed: ' + error.message));
            \`;
            const url = URL.createObjectURL(new Blob([source], { type: 'text/javascript' }));
            const worker = new Worker(url, { type: 'module' });
            worker.onmessage = event => log.textContent += '\\n' + event.data;
            worker.onerror = event => log.textContent += '\\nworker error: ' + event.message;
          </script>
        </body>
      </html>`;
  }));
}
// media/worker-module.js
export const loaded = true;

Diagnosis

#311844 (merged 2026-04-22) relaxed the guard in the
webview service worker so that client.type === 'worker' | 'sharedworker'
reaches processResourceRequest / processLocalhostRequest:

https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/webview/browser/pre/service-worker.js#L307-L313

But the dispatch block only routes when webviewId is non-null:

https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/webview/browser/pre/service-worker.js#L431-L450

For a blob worker created inside a webview iframe, client.url is
blob:https://<hash>.vscode-webview.net/<uuid> — no id searchParam —
so getWebviewIdForClient returns null. The relaxed guard lets that
through, but if (webviewId) is skipped, no postMessage is sent to
the host iframe, the resourceRequestStore entry is never resolved,
and the fetch hangs until requestTimeout() fires.

processLocalhostRequest (lines 460–517) has the same shape and the
same dead-end for worker clients.

Proposed direction

A worker created inside a webview iframe shares the iframe's origin
(blob URLs inherit their creator origin). Resolving the owning iframe
via origin match seems like the smallest fix for the common case, as
long as the service worker only routes when that origin maps to a single
webview id. If multiple webviews share an origin, it should fail closed
instead of sending the request to an arbitrary iframe. Draft PR coming.

Metadata

Metadata

Assignees

Labels

bugIssue identified by VS Code Team member as probable bug

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions