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
Open
fix: don't report failed web openTunnel as a bug assertion (fixes #321637)#321644vs-code-engineering[bot] wants to merge 1 commit into
vs-code-engineering[bot] wants to merge 1 commit into
Conversation
…1637) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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
The web embedder
openTunnelAPI (IWorkbench.workspace.openTunnel) wrappedremoteExplorerService.forward()inassertReturnsDefined(). Becauseforward()legitimately resolves toundefinedwhen a tunnel cannot be opened, the assertion throws aBugIndicatingError("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:
@alexr00Culprit Commit
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 telemetryAffected Files
src/vs/workbench/browser/web.main.tsconst tunnel = assertReturnsDefined(await remoteExplorerService.forward({...}))— synthesizes theBugIndicatingErrorfrom a legitimateundefinedsrc/vs/workbench/services/remote/common/tunnelModel.tsundefined)forward()/doForward()typedPromise<RemoteTunnel | string | undefined>;return noTunnelValue(undefined) when the tunnel can't be opened / has no local addresssrc/vs/base/common/types.tsassertReturnsDefined→assert(...)src/vs/base/common/assert.tsassert(false, msg)throwsnew BugIndicatingError('Assertion Failed: ' + msg)src/vs/base/common/errors.tsErrorNoTelemetry(excluded from unhandled-error telemetry); L332BugIndicatingError(reported as a bug)Repro Steps
This is a deterministic failure of the embedder API whenever
forward()yields no tunnel:IWorkbenchembedder API (e.g.vscode-web), configured with a remote authority / managed tunnel factory.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.remoteExplorerService.forward(...)resolves toundefined.assertReturnsDefined(undefined)throwsBugIndicatingError: Assertion Failed: Argument is undefined or null..How the Fix Works
Chosen approach (
src/vs/workbench/browser/web.main.ts): Remove theassertReturnsDefinedwrapper aroundforward()and handle its documentedundefinedreturn explicitly. Whenforward()resolves toundefined, throw a diagnosticErrorNoTelemetrythat names the remotehost:port:The fix lives at the place that mis-escalates a legitimate outcome into a product-bug assertion. The data producer is correct —
undefinedis a valid, documented return offorward()consumed by many callers — so the fix belongs at the consumer that misclassifies it, not at the crash site inassert.ts/types.ts(fix at the data producer of the bad behaviour, not at the symptom).ErrorNoTelemetryis 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 unusedassertReturnsDefinedimport is removed.Why this fix works: after this change,
web.main.tsopenTunnelcannot produce aBugIndicatingErrorfor a failed tunnel, because theassertReturnsDefinedcall that synthesized it has been removed and a legitimately-undefinedforward()result now throws a descriptiveErrorNoTelemetry— an expected, non-telemetered failure the embedder handles.Alternatives considered:
Error('Could not open tunnel ...')— rejected: the error is reported as an unhandled rejection, so a plainError(like the currentBugIndicatingError) 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.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.forward()to never returnundefined— rejected:undefinedis its documented "no tunnel" contract relied on by many callers; the producer is not buggy.Recommended Owner
@alexr00— owns "Ports view/forwarding" in the authoritativemicrosoft/vscode-engineeringtriage/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).