Skip to content

fix: clamp inverted visible range in ListView to prevent RangeError (fixes #333230) - #333236

Merged
Connor Peet (connor4312) merged 6 commits into
microsoft:mainfrom
vscodebot-pr:fix/listview-invalid-array-length-333230-aw-33202685801
Aug 31, 2026
Merged

fix: clamp inverted visible range in ListView to prevent RangeError (fixes #333230)#333236
Connor Peet (connor4312) merged 6 commits into
microsoft:mainfrom
vscodebot-pr:fix/listview-invalid-array-length-333230-aw-33202685801

Conversation

@vscodebot-pr

Copy link
Copy Markdown

Summary

RangeError: Invalid array length is thrown in ListView.probeDynamicHeights (src/vs/base/browser/ui/list/listView.ts) when it evaluates new Array<number>(range.end - range.start) with an inverted range (end < start). The negative length throws immediately.

The inverted range originates in getVisibleRange(renderTop, renderHeight). When the viewport is collapsed or hidden during a layout pass (renderHeight <= 0), the expression renderTop + renderHeight - 1 becomes smaller than renderTop. Because rangeMap.indexAfter(position) = min(indexAt(position) + 1, count) is monotonic in position, the resulting end can resolve to an index before start, yielding { start, end } with end < start. This malformed IRange violates the start <= end invariant that consumers assume.

This is a recent regression (new bucket in 1.135.0, 411 users): the previous _rerender iterated with for (let i = range.start; i < range.end; i++), which silently tolerated an inverted range by not iterating. The batched-measurement rewrite replaced that loop with an eagerly-sized array, turning the previously-harmless inverted range into a hard crash.

Fixes #333230
Recommended reviewer: @connor4312

Culprit Commit

c2b336daae7101676f179b30f92641cdfcc6b38c — "list: batch dynamic height measurements (#330967)" by Connor Peet (connor4312), 2026-08-18. This commit falls within the reported regression range (0d0c8a6...68161d9, 1.134.0-insider → 1.135.0-insider) and introduced probeDynamicHeights, which allocates new Array<number>(range.end - range.start) without guaranteeing end >= start.

Code Flow

flowchart TD
    A[layout / setScrollDimensions with renderHeight <= 0] --> B[onScroll]
    B --> C[_rerender]
    C --> D["getVisibleRange(renderTop, renderHeight)"]
    D --> E["end = indexAfter(renderTop + renderHeight - 1)<br/>can be < start when renderHeight &le; 0"]
    E --> F["inverted IRange: end < start"]
    F --> G["probeDynamicHeights(range)"]
    G --> H["new Array(range.end - range.start)<br/>negative length"]
    H --> I["RangeError: Invalid array length"]
Loading

Affected Files

  • src/vs/base/browser/ui/list/listView.tsgetVisibleRange (producer of the inverted range) and probeDynamicHeights (crash site).

Repro Steps

Not reliably reproducible via manual steps; occurs under a layout race. Conceptually:

  1. Host a ListView inside a widget whose container can be laid out with zero/negative height (e.g., a collapsed chat/inline-chat widget).
  2. Trigger a layout/scroll pass while renderHeight <= 0.
  3. getVisibleRange returns an inverted range; probeDynamicHeights allocates a negative-length array and throws RangeError: Invalid array length.

How the Fix Works

Chosen approachsrc/vs/base/browser/ui/list/listView.ts, getVisibleRange: compute start first, then clamp end with Math.max(start, indexAfter(renderTop + renderHeight - 1)). This fixes the bug at the data producer rather than at the crash site: getVisibleRange constructs the IRange, so enforcing the start <= end invariant there guarantees every consumer (including probeDynamicHeights) receives a well-formed range. An empty range (start === end) is valid and yields a zero-length array, restoring the harmless behavior the previous for-loop had.

After this change, getVisibleRange cannot produce a range with end < start because end is explicitly clamped to be at least start, so range.end - range.start is always >= 0 and new Array(...) can no longer receive a negative length.

Alternatives considered:

  • Guard at the crash site in probeDynamicHeights (e.g., early-return or clamp the array length there) — rejected because it patches the symptom at the bottom of the stack while leaving the malformed IRange flowing to every other consumer; the fix must live where the invalid data is produced.

Recommended Owner

connor4312 (Connor Peet) — authored the culprit commit c2b336daae71 and is an active repository collaborator with recent commits.

Generated by errors-fix · opus48 · 452.1 AIC · ⌖ 11.3 AIC · ⊞ 18.6K ·

…ixes microsoft#333230)

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

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

Benjamin Christopher Simmonds (@benibenj)

Matched files:

  • src/vs/base/browser/ui/list/listView.ts

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.

Pull request overview

Prevents ListView crashes when collapsed viewports produce inverted visible ranges.

Changes:

  • Reuses the calculated visible-range start.
  • Clamps the range end to preserve start <= end.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/vs/base/browser/ui/list/listView.ts
Comment thread src/vs/base/browser/ui/list/listView.ts Outdated
…ession test

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

Copy link
Copy Markdown
Contributor
Driver cycle recordederrors-fix-driver:cycle head:61d2314e92f40910223a7165019ff720fcb55d6f

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/vs/base/test/browser/ui/list/listView.test.ts Outdated
Restore the accidentally-removed teardown/closing of the shift-click
selection test and rewrite the zero-height regression test so it actually
triggers the inverted range: with zero-height dynamic items and a
collapsed viewport, getVisibleRange previously produced { start: 3, end: 0 }
which crashed probeDynamicHeights.

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

Copy link
Copy Markdown
Contributor
Driver cycle recordederrors-fix-driver:cycle head:055d71cef5eba530c7fb14a37e5740c3a7edb886

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/vs/base/test/browser/ui/list/listView.test.ts Outdated
…ment to one line

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

Copy link
Copy Markdown
Contributor
Driver cycle recordederrors-fix-driver:cycle head:cb7a02b2b836eb7516cb2809aeef241e2c48caa2

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@vs-code-engineering

Copy link
Copy Markdown
Contributor

The Screenshots & Tests (Component Fixtures) check failed only at the Determine base SHA step (git merge-base on a shallow fork fetch) — all Playwright fixture tests and screenshot captures passed, and this step is unrelated to this PR's listView.ts clamp fix. This run is already on attempt 2 and the automation lacks actions: write, so a maintainer rerun of that check is needed.

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@connor4312
Connor Peet (connor4312) merged commit 193cdec into microsoft:main Aug 31, 2026
27 checks passed
@vs-code-engineering vs-code-engineering Bot added this to the 1.137.0 milestone Aug 31, 2026
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-Invalid array length

5 participants