Skip to content

fix: don't report failed web openTunnel as a bug assertion (fixes #321637)#321644

Open
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/web-opentunnel-bugindicating-321637-433821aec50c2e50
Open

fix: don't report failed web openTunnel as a bug assertion (fixes #321637)#321644
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/web-opentunnel-bugindicating-321637-433821aec50c2e50

Conversation

@vs-code-engineering

Copy link
Copy Markdown
Contributor

Summary

The web embedder openTunnel API (IWorkbench.workspace.openTunnel) wrapped remoteExplorerService.forward() in assertReturnsDefined(). Because forward() legitimately resolves to undefined when a tunnel cannot be opened, the assertion throws a BugIndicatingError ("Assertion Failed: Argument is undefined or null.") that is reported to error telemetry as an unhandled product bug — even though "no tunnel could be opened" is an expected, embedder-handleable operational failure. This misclassifies an environmental failure as a VS Code defect and floods bug telemetry heavily (103k+ hits / 72k+ users across stable releases since 1.112).

Fixes #321637
Recommended reviewer: @alexr00

Culprit Commit

No single culprit commit — pre-existing, long-standing misclassification (not a recent regression). The openTunnel embedder API has wrapped forward() in assertIsDefined/assertReturnsDefined since well before the reported version 1.124.2. Bucket history shows hits in every tracked stable release — 1.112.0 (8,345), 1.115.0 (37,534), 1.120.0 (10,666), 1.121.0 (7,589), ... — totalling 103,718 hits / 72,164 users, a chronic signal rather than an anomaly tied to one commit. The recent-regression / stable-anomaly labels are auto-applied dashboard heuristics. The fix targets the misclassification directly; no regression commit needs to be reverted.

Code Flow

sequenceDiagram
    participant Embedder as Host page (embedder)
    participant OpenTunnel as web.main.ts openTunnel
    participant Forward as tunnelModel forward()
    participant Assert as assertReturnsDefined / assert

    Embedder->>OpenTunnel: openTunnel({ remoteAddress })
    OpenTunnel->>Forward: forward(remote, options)
    Note over Forward: ⚠️ Root cause:<br/>resolves to undefined when no tunnel<br/>can be opened (legitimate "no tunnel" value)
    Forward-->>OpenTunnel: undefined
    OpenTunnel->>Assert: assertReturnsDefined(undefined)
    Note over Assert: 💥 BugIndicatingError thrown:<br/>"Assertion Failed: Argument is undefined or null."
    Assert-->>Embedder: unhandled rejection → reported to bug telemetry
Loading

Affected Files

File Role Evidence
src/vs/workbench/browser/web.main.ts crash site + fix L222 (pre-fix): const tunnel = assertReturnsDefined(await remoteExplorerService.forward({...})) — synthesizes the BugIndicatingError from a legitimate undefined
src/vs/workbench/services/remote/common/tunnelModel.ts root cause (producer of the legitimate undefined) L698-L762: forward()/doForward() typed Promise<RemoteTunnel | string | undefined>; return noTunnelValue (undefined) when the tunnel can't be opened / has no local address
src/vs/base/common/types.ts assertion helper (unchanged) L117: assertReturnsDefinedassert(...)
src/vs/base/common/assert.ts throw origin (unchanged) L44: assert(false, msg) throws new BugIndicatingError('Assertion Failed: ' + msg)
src/vs/base/common/errors.ts telemetry classification (unchanged) L303 ErrorNoTelemetry (excluded from unhandled-error telemetry); L332 BugIndicatingError (reported as a bug)

Repro Steps

This is a deterministic failure of the embedder API whenever forward() yields no tunnel:

  1. Run VS Code for the Web through an embedder that uses the IWorkbench embedder API (e.g. vscode-web), configured with a remote authority / managed tunnel factory.
  2. From the host page, call workbench.workspace.openTunnel({ remoteAddress: { host, port } }) for a remote address that cannot be tunneled — i.e. no managed tunnel factory can satisfy the request, or the created tunnel has no local address.
  3. remoteExplorerService.forward(...) resolves to undefined.
  4. assertReturnsDefined(undefined) throws BugIndicatingError: Assertion Failed: Argument is undefined or null..
  5. The rejection is unhandled and reported to error telemetry (observed as the bucket in this issue: 103k+ hits / 72k+ users across stable releases since 1.112).

How the Fix Works

Chosen approach (src/vs/workbench/browser/web.main.ts): Remove the assertReturnsDefined wrapper around forward() and handle its documented undefined return explicitly. When forward() resolves to undefined, throw a diagnostic ErrorNoTelemetry that names the remote host:port:

const tunnel = await remoteExplorerService.forward({ ... }, { ... });

if (tunnel === undefined) {
    throw new ErrorNoTelemetry(`Could not open tunnel to ${tunnelOptions.remoteAddress.host}:${tunnelOptions.remoteAddress.port}.`);
}

if (typeof tunnel === 'string') {
    throw new Error(tunnel);
}

The fix lives at the place that mis-escalates a legitimate outcome into a product-bug assertion. The data producer is correct — undefined is a valid, documented return of forward() consumed by many callers — so the fix belongs at the consumer that misclassifies it, not at the crash site in assert.ts/types.ts (fix at the data producer of the bad behaviour, not at the symptom). ErrorNoTelemetry is the purpose-built class for an expected error that should still reject the promise (so the embedder can handle the failure and surface its own UI) but must not be logged as an unhandled product bug. The parallel string-error branch (throw new Error(tunnel)) is preserved unchanged, and the unused assertReturnsDefined import is removed.

Why this fix works: after this change, web.main.ts openTunnel cannot produce a BugIndicatingError for a failed tunnel, because the assertReturnsDefined call that synthesized it has been removed and a legitimately-undefined forward() result now throws a descriptive ErrorNoTelemetry — an expected, non-telemetered failure the embedder handles.

Alternatives considered:

  • Throw a plain Error('Could not open tunnel ...') — rejected: the error is reported as an unhandled rejection, so a plain Error (like the current BugIndicatingError) is still logged to telemetry; it would rename the bucket without removing the 103k-hit noise, and still frames an expected failure as an unhandled error.
  • Guard inside assertReturnsDefined / assert (the crash site) — rejected: those are shared utilities used across the codebase; weakening them would hide genuine bugs elsewhere and fixes the symptom rather than the misclassification.
  • Change forward() to never return undefined — rejected: undefined is its documented "no tunnel" contract relied on by many callers; the producer is not buggy.

Recommended Owner

@alexr00 — owns "Ports view/forwarding" in the authoritative microsoft/vscode-engineering triage/working-areas.md (Step 5 cascade step 2, feature-area owner). Team Membership gate: pass — core VS Code maintainer with direct write access (commits merged directly). Liveness gate: pass — active, commits through 2026-06-16. The culprit-author cascade step was skipped (pre-existing bug, no single culprit commit).

Generated by errors-fix · 2.8K AIC · ⌖ 227.6 AIC · ⊞ 69.2K ·

…1637)

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

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 requested review from alexr00 and Copilot June 16, 2026 17:24

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 16, 2026 17:25
@vs-code-engineering vs-code-engineering Bot enabled auto-merge (squash) June 16, 2026 17: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-Assertion Failed: Argument is undefined or null.

2 participants