Skip to content

fix: guard against empty viewport range in diff editor gutter clip (fixes #316032)#316038

Open
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/empty-viewport-range-clip-316032-295ce1c27895c02d
Open

fix: guard against empty viewport range in diff editor gutter clip (fixes #316032)#316038
vs-code-engineering[bot] wants to merge 1 commit into
mainfrom
fix/empty-viewport-range-clip-316032-295ce1c27895c02d

Conversation

@vs-code-engineering
Copy link
Copy Markdown
Contributor

@vs-code-engineering vs-code-engineering Bot commented May 12, 2026

🔧 Error Fix

Summary

Property Value
Error Invalid clipping range: [37, 37)
Bucket 5c896f3a-1b03-ede7-83e9-9035cdc4464d
Hits / Users (1.119.0) 2800 / 780
Platforms Mac, Windows, Linux

The diff editor gutter layout code calls OffsetRange.clip() on preferredViewPortRange without first verifying that the range is non-empty. OffsetRange.tryCreate() returns undefined only when start > endExclusive, but returns an empty range (start === endExclusive) as a valid object. The existing guard checked nullability and that preferredParentRange was non-empty, but missed checking preferredViewPortRange for emptiness. When preferredViewPortRange is empty (e.g., [37, 37)), clip() throws BugIndicatingError.

Fixes #316032
Recommended reviewer: @hediet

Culprit Commit

This is a long-standing bug, not a recent regression. The incomplete guard has been present since the gutter feature was originally authored by @hediet. The error appears across multiple versions (1.112.0 through 1.119.0).

Code Flow

graph TD
    A["ResizeObserver callback"] --> B["editorGutter.ts: render()"]
    B --> C["editorGutter.ts: transaction()"]
    C --> D["gutterFeature.ts: layout() :313"]
    D --> E{"preferredViewPortRange non-null?"}
    E -->|yes| F{"preferredParentRange non-empty?"}
    F -->|yes| G["preferredViewPortRange.clip() :313"]
    G --> H["offsetRange.ts: clip() :170"]
    H --> I{"this.isEmpty?"}
    I -->|yes - BUG| J["throw BugIndicatingError"]
Loading

Affected Files

  • src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts — missing emptiness check for preferredViewPortRange
  • src/vs/editor/common/core/ranges/offsetRange.tsclip() correctly throws on empty range (not a bug here)

Repro Steps

  1. Open a diff editor in VS Code
  2. Resize the editor such that the viewport range becomes very small (margin values cause endExclusive - margin - itemHeight to equal margin)
  3. The gutter layout triggers via ResizeObserver and preferredViewPortRange is created as an empty range [N, N)
  4. clip() is called on the empty range, throwing the error

How the Fix Works

Chosen approach (src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts): Added !preferredViewPortRange.isEmpty to the guard condition at line 312, alongside the existing preferredParentRange non-empty check. Also replaced the manual start < endExclusive comparison with the idiomatic .isEmpty property for both ranges. This fixes at the data producer (the guard that decides whether to call clip()), not the crash site (clip() itself), following the principle of fixing where invalid data flows into the throwing function.

Recommended Owner

@hediet — author and maintainer of the diff editor gutter feature code.

errors-fix-driver — cycle 11

Trigger: cron_review_comments · Head: c61f61b81c49f0337860f6a968a0f484c167b130 (c61f61b)

Item Action
CI (all checks) ✅ All passing
Review threads None (0 unresolved)
Merge state blocked (awaiting human approval)

Push: no (nothing to fix) · Copilot rerequested: no (no push)

Ready gate: PR already marked ready; awaiting human approval from @hediet.

errors-fix-driver — cycle 12

Trigger: cron_review_comments · Head: c61f61b81c49f0337860f6a968a0f484c167b130 (c61f61b)

Item Action
CI (all checks) ✅ All passing
Review threads None (0 unresolved)
Merge state blocked (awaiting human approval)

Push: no (nothing to fix) · Copilot rerequested: no (no push)

Ready gate: PR already marked ready; awaiting human approval from @hediet.

errors-fix-driver — cycle 13

Trigger: cron_review_comments · Head: c61f61b81c49f0337860f6a968a0f484c167b130 (c61f61b)

Item Action
CI (all checks) ✅ All passing
Review threads None (0 unresolved)
Merge state blocked (awaiting human approval)

Push: no (nothing to fix) · Copilot rerequested: no (no push)

Ready gate: PR already marked ready; awaiting human approval from @hediet.

Generated by errors-fix-driver · ● 6.3M ·

…ixes #316032)

The guard at line 312 checked that preferredParentRange was non-empty
but did not check preferredViewPortRange. When preferredViewPortRange
had start === endExclusive (empty range), it passed the truthiness
check but OffsetRange.clip() threw 'Invalid clipping range'.

Also use the idiomatic .isEmpty property instead of manual start < end
comparison for both ranges.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 12, 2026 16:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 Copilot and hediet May 12, 2026 16:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 May 12, 2026 16:06
@vs-code-engineering vs-code-engineering Bot enabled auto-merge (squash) May 13, 2026 17:28
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 clipping range: [37, 37)

2 participants