Skip to content

fix: drop empty MessagePort frames instead of forwarding unparseable buffers (fixes #326171) - #326172

Merged
vs-code-engineering[bot] merged 2 commits into
mainfrom
fix/ipc-mp-empty-frame-326171-0985e638956ef403
Jul 17, 2026
Merged

fix: drop empty MessagePort frames instead of forwarding unparseable buffers (fixes #326171)#326172
vs-code-engineering[bot] merged 2 commits into
mainfrom
fix/ipc-mp-empty-frame-326171-0985e638956ef403

Conversation

@vs-code-engineering

@vs-code-engineering vs-code-engineering Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

TypeError: Cannot read properties of undefined (reading '0') is thrown from the IPC protocol reader in src/vs/base/parts/ipc/common/ipc.ts. Two coalesced buckets hit the same root cause from both directions of the channel:

  • c161d9c4ChannelClient.onBufferipc.ts:757 (const type = header[0])
  • a0fde558ChannelServer.onRawMessageipc.ts:398 (const type = header[0])

In both cases header = deserialize(reader) returns undefined, then header[0] throws. deserialize returns undefined when it reads a message whose first byte cannot be matched to a DataType — most notably when the incoming VSBuffer is zero-length: reader.read(1) yields an empty buffer, readUInt8(0) yields undefined, the switch falls through, and deserialize returns undefined.

The zero-length buffer is manufactured by the MessagePort transport in src/vs/base/parts/ipc/common/ipc.mp.ts. When a message event arrives with no (or empty) data, the old code returned VSBuffer.alloc(0) and forwarded it through onMessage into 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: @deepak1556

Culprit Commit

ipc.mp.ts and ipc.ts were not modified inside the flagged regression window (1a31eba2...e8a3eada, 2026-07-10). The empty-frame → alloc(0) fallback is long-standing (introduced by 972172bc "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]
Loading

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 readers onBuffer (line 757) and onRawMessage (line 398); crash sites (not modified).

Repro Steps

  1. Run VS Code desktop where a channel client/server communicates over a MessagePort (utility/shared process connections).
  2. Cause the port to deliver a message event whose data is null or a zero-length Uint8Array (e.g. during connection teardown / process shutdown).
  3. The transport forwards a zero-length VSBuffer; deserialize returns undefined; header[0] throws the unhandled TypeError.

How the Fix Works

Chosen approachsrc/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. The message map now returns VSBuffer | undefined (undefined when there is no data), and an Event.filter drops any value that is missing or has byteLength === 0. After this change, Protocol.onMessage can no longer emit a zero-length buffer, so ChannelClient.onBuffer (ipc.ts:755) and ChannelServer.onRawMessage (ipc.ts:396) can no longer receive a buffer that deserialize turns into an undefined header — the header[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/catch is added, no logService.error is removed, and the typed deserialize utility 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:

  • Guarding at the crash site in 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.
  • Changing deserialize to 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/null data handling in ipc.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.

Generated by errors-fix · 1.9K AIC · ⌖ 34.1 AIC · ⊞ 70.8K ·


errors-fix-driver — cycle 1

Trigger: cron_check_failed · Head: 3c1f71f352f5cedc1f46d480430c4f52e91f52f2 (3c1f71f)

Item Action
CI: Compile & Hygiene (real — tsc type error) Fixed in 3c1f71f

The Compile & Hygiene job was the only check running full tsc type-checking (the platform matrix jobs transpile-only), so it alone surfaced the error. The type-guard overload of Event.filter over Event<VSBuffer | undefined> resolved to the boolean overload, widening the inferred Protocol.onMessage property to Event<VSBuffer | undefined>, which is not assignable to the base IMessagePassingProtocol.onMessage: Event<VSBuffer>. Reworked the transport so the mapped event stays Event<VSBuffer> (empty data maps to VSBuffer.alloc(0)) and empty frames are dropped with a plain boolean Event.filter(onMessage, data => data.byteLength > 0) — unambiguous overload, identical drop-empty-frames behavior.

Push: yes — 3c1f71f · Copilot rerequested: ok

Ready 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.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "electronjs.org"

See Network Configuration for more information.

Generated by errors-fix-driver · 1.4K AIC · ⌖ 33.5 AIC · ⊞ 72.7K ·

…buffers (fixes #326171)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 16, 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.

Copilot can't review bot-authored pull requests automatically. A user with Copilot access can request a review manually.

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 can't review bot-authored pull requests automatically. A user with Copilot access can request a review manually.

@vs-code-engineering
vs-code-engineering Bot marked this pull request as ready for review July 16, 2026 15:55
@vs-code-engineering
vs-code-engineering Bot enabled auto-merge (squash) July 16, 2026 15:55
…ames on Event<VSBuffer>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-code-engineering

Copy link
Copy Markdown
Contributor Author

Commit pushed: bac2202

Generated by errors-fix-driver · 1.4K AIC · ⌖ 33.5 AIC · ⊞ 72.7K

@vs-code-engineering
vs-code-engineering Bot requested a review from Copilot July 16, 2026 16:51

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 can't review bot-authored pull requests automatically. A user with Copilot access can request a review manually.

@deepak1556 deepak1556 added this to the 1.130.0 milestone Jul 17, 2026
@vs-code-engineering
vs-code-engineering Bot merged commit 07be076 into main Jul 17, 2026
29 checks passed
@vs-code-engineering
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
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-Cannot read properties of undefined (reading '0')

4 participants