fix: drop empty MessagePort frames instead of forwarding unparseable buffers (fixes #326171) - #326172
Merged
vs-code-engineering[bot] merged 2 commits intoJul 17, 2026
Conversation
…buffers (fixes #326171) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ames on Event<VSBuffer> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
|
Commit pushed:
|
deepak1556
approved these changes
Jul 17, 2026
pwang347
approved these changes
Jul 17, 2026
benvillalobos
approved these changes
Jul 17, 2026
vs-code-engineering
Bot
deleted the
fix/ipc-mp-empty-frame-326171-0985e638956ef403
branch
July 17, 2026 19:57
jpolitz
added a commit
to jpolitz/pyret-lang
that referenced
this pull request
Jul 29, 2026
Joe says: Based on the typespec issue listed below, I'm pretty sure we hit some kind of racy flake in VScode itself (separate commits fix our own race issues). This commit forces our testing environment to use the same commit of vscode that typespec went back to in order to fix their issue. Claude says: @vscode/test-web downloads the LATEST stable VS Code build at test time, so every CI run floats on whatever Microsoft shipped last. VS Code 1.130.0 (commit 1b6a188127ee) was released 2026-07-22; on that build the vscode env intermittently dies at boot: the .arr tab opens, the web extension host starts, but resolveCustomTextEditor is never invoked -- no webview iframe, no error, no notification -- until the harness's 120s bound trips. Only the dev-extension jobs (vscode, both flavors) hit it; the ovsx jobs, whose extension installs as a packaged VSIX and so is registered before the workbench opens the file, never do. The suite was green for weeks on 1.129.1 (8a7abeba6e03) and this exact harness code has both green and red runs on 1.130.0, so the trigger is the build rollover, not a commit of ours. Independent confirmation: microsoft/typespec's vscode e2e suites (web and desktop) started hanging the same day, were disabled to unblock CI, and were re-enabled by pinning to this same 8a7abeba build: microsoft/typespec#11369 microsoft/typespec#11383 The 1.130 release notes mention nothing about custom editors or the web extension host, but the same race family exists upstream -- a file opened at launch can resolve before a contributed custom editor is registered, and a custom-editor open with no registered provider spins forever with no error: microsoft/vscode#325506 microsoft/vscode#96407 https://code.visualstudio.com/updates/v1_130 1.130.0 changes plausibly retiming startup: the MessagePort IPC layer now drops unparseable frames instead of erroring, and webview resource loading gained a global stream semaphore: microsoft/vscode#326172 microsoft/vscode#326272 The pin also makes this env deterministic, which "latest stable" never was. Revisit when a post-1.130.0 stable proves green; as of today no upstream issue tracks this regression, so ours may be the first report. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UWehNoCfHncXSWk6D3DFeQ
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
TypeError: Cannot read properties of undefined (reading '0')is thrown from the IPC protocol reader insrc/vs/base/parts/ipc/common/ipc.ts. Two coalesced buckets hit the same root cause from both directions of the channel:c161d9c4—ChannelClient.onBuffer→ipc.ts:757(const type = header[0])a0fde558—ChannelServer.onRawMessage→ipc.ts:398(const type = header[0])In both cases
header = deserialize(reader)returnsundefined, thenheader[0]throws.deserializereturnsundefinedwhen it reads a message whose first byte cannot be matched to aDataType— most notably when the incomingVSBufferis zero-length:reader.read(1)yields an empty buffer,readUInt8(0)yieldsundefined, theswitchfalls through, anddeserializereturnsundefined.The zero-length buffer is manufactured by the MessagePort transport in
src/vs/base/parts/ipc/common/ipc.mp.ts. When amessageevent arrives with no (or empty)data, the old code returnedVSBuffer.alloc(0)and forwarded it throughonMessageinto the channel readers, which cannot parse an empty frame. An empty frame is never a valid protocol message (the smallest valid frame still carries a serialized header), so it must be dropped at the transport boundary rather than delivered.Fixes #326171
Recommended reviewer:
@deepak1556Culprit Commit
ipc.mp.tsandipc.tswere not modified inside the flagged regression window (1a31eba2...e8a3eada, 2026-07-10). The empty-frame →alloc(0)fallback is long-standing (introduced by972172bc"fix: for message event data can be null"). The 22x spike in 1.129.0 was therefore triggered by an upstream component that began delivering empty MessagePort frames more frequently; that producer could not be pinned down from the available signal within budget. The transport-boundary handling of empty frames is the deterministic point where the invalid (empty) buffer enters the channel pipeline, and is fixed here.Code Flow
flowchart TD A[MessagePort 'message' event with empty/null data] --> B[Protocol.onMessage in ipc.mp.ts] B -->|returns VSBuffer.alloc 0| C[ChannelClient.onBuffer / ChannelServer.onRawMessage] C --> D[deserialize reads no valid type byte] D -->|returns undefined| E[const type = header 0] E --> F[TypeError: Cannot read properties of undefined reading 0]Affected Files
src/vs/base/parts/ipc/common/ipc.mp.ts— MessagePort transport; produces the empty buffer (fixed here).src/vs/base/parts/ipc/common/ipc.ts— channel readersonBuffer(line 757) andonRawMessage(line 398); crash sites (not modified).Repro Steps
MessagePort(utility/shared process connections).messageevent whosedatais null or a zero-lengthUint8Array(e.g. during connection teardown / process shutdown).VSBuffer;deserializereturnsundefined;header[0]throws the unhandledTypeError.How the Fix Works
Chosen approach —
src/vs/base/parts/ipc/common/ipc.mp.ts: filter empty frames out at the transport boundary so they are never forwarded to the channel readers. Themessagemap now returnsVSBuffer | undefined(undefinedwhen there is no data), and anEvent.filterdrops any value that is missing or hasbyteLength === 0. After this change,Protocol.onMessagecan no longer emit a zero-length buffer, soChannelClient.onBuffer(ipc.ts:755) andChannelServer.onRawMessage(ipc.ts:396) can no longer receive a buffer thatdeserializeturns into anundefinedheader — theheader[0]read is unreachable for empty input.This fixes the data at the point it enters our pipeline (the producer of the invalid empty buffer) rather than guarding the crash site: no
try/catchis added, nologService.erroris removed, and the typeddeserializeutility body is untouched. Dropping an empty frame loses no information because a zero-byte frame could never have encoded a valid message (a valid frame is always at least a header byte plus a body byte).Alternatives considered:
onBuffer/onRawMessage(e.g.if (!header) return) — rejected: that guards the consumer/crash site and hides where the bad buffer originates instead of stopping it at the producer.deserializeto tolerate an empty reader — rejected: that patches a shared, typed serialization utility to absorb malformed input, masking the transport-level defect for every caller.Recommended Owner
@deepak1556— authored the MessagePort empty/nulldatahandling inipc.mp.ts(972172bc, "fix: for message event data can be null") and related MessagePort transport work, making them the closest owner for this transport-boundary change.errors-fix-driver — cycle 1
Trigger: cron_check_failed · Head:
3c1f71f352f5cedc1f46d480430c4f52e91f52f2(3c1f71f)Compile & Hygiene(real —tsctype error)3c1f71fThe
Compile & Hygienejob was the only check running fulltsctype-checking (the platform matrix jobs transpile-only), so it alone surfaced the error. The type-guard overload ofEvent.filteroverEvent<VSBuffer | undefined>resolved to the boolean overload, widening the inferredProtocol.onMessageproperty toEvent<VSBuffer | undefined>, which is not assignable to the baseIMessagePassingProtocol.onMessage: Event<VSBuffer>. Reworked the transport so the mapped event staysEvent<VSBuffer>(emptydatamaps toVSBuffer.alloc(0)) and empty frames are dropped with a plain booleanEvent.filter(onMessage, data => data.byteLength > 0)— unambiguous overload, identical drop-empty-frames behavior.Push: yes —
3c1f71f· Copilot rerequested: okReady gate: CI pending after push → not evaluating ready this cycle.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
electronjs.orgSee Network Configuration for more information.