You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
IndentGuidesOverlay.prepareRender crashes with TypeError: Cannot read properties of null (reading 'left') at indentGuides.ts:138 because it dereferences the result of ctx.visibleRangeForPosition(...) with a non-null assertion (!.left), while that method's declared contract is HorizontalPosition | null. When a guide's column has no visible range in the current frame (position not yet laid out, GPU/DOM viewline transition, or scroll/wrap edge), the method legitimately returns null and the ! bypass throws. Notably, every sibling call to visibleRangeForPosition in the same function already handles null safely (?.left ?? 0 on the leftOffset at line 132, and ?.left ?? (left + this._spaceWidth) for the horizontal-line width at lines 154-157) — only the vertical-guide left computation used the unsafe !.
The non-null assertion pattern predates the current telemetry window and lives in the editor indent-guides rendering path. The closest owning change is the line-height refactoring series by @hediet (a9ab31d "Refactors: Reduces assumptions about line height." and its reapply 5faa55a), which reworked how guide columns map to visible ranges. The exact introduction of the ! could not be pinned down precisely because the working tree is a shallow clone (depth 1), so git blame history is unavailable. The bug is a latent contract violation rather than a fresh regression.
Code Flow
sequenceDiagram
participant DOM as dom.ts scheduler
participant ViewPart as view.ts
participant Overlays as viewOverlays.ts
participant Guides as indentGuides.ts prepareRender
participant Ctx as RenderingContext
DOM->>ViewPart: safeInvokeNoArg -> prepareRender
ViewPart->>Overlays: prepareRender(ctx)
Overlays->>Guides: prepareRender(ctx)
Guides->>Ctx: visibleRangeForPosition(Position(line, guide.column))
Ctx-->>Guides: null (no visible range this frame)
Note over Guides: null! .left -> TypeError
Loading
Affected Files
src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts — prepareRender guide loop: replaced the unsafe non-null assertion with a null check.
Repro Steps
Not reliably reproducible on demand; it is a timing/layout-edge crash. It occurs when prepareRender runs for a guide whose column is not currently resolvable to a visible range — e.g. during rapid scrolling, viewline recycling, GPU renderer transitions, or wrapped-line layout churn while indent/bracket-pair guides are enabled. Telemetry shows real-world hits from the editor render loop (view.ts -> viewOverlays.ts -> indentGuides.ts).
How the Fix Works
Chosen approach (src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts): The left computation for a guide with a real model column (guide.column !== -1) previously did ctx.visibleRangeForPosition(new Position(lineNumber, guide.column))!.left. The ! is the type-system bypass: it asserts non-null on a value the method's signature declares as HorizontalPosition | null. This is fixed at the bypass site itself — not at a downstream reader and not by coercing to a benign default — by removing the assertion, checking the returned value, and continue-ing the guide loop when the range is absent so the guide is simply not emitted for this frame (it renders on the next frame once layout resolves). This matches the existing null-handling already used by every other visibleRangeForPosition call in the same function, so behavior is consistent and no error is masked: visibleRangeForPosition returning null is a legitimate, expected outcome of its contract, not invalid data produced upstream. There is no "producer of bad data" to fix — the producer already correctly returns null; the consumer's ! was the defect.
After this change, indentGuides.ts:138 cannot produce the TypeError because the code no longer dereferences the return value of visibleRangeForPosition without first confirming it is non-null; the continue path skips the guide instead.
Alternatives considered: Falling back to leftOffset/0 like line 132 was rejected because a guide whose column is not layout-resolvable would be painted at the wrong x-position (visual glitch) rather than omitted; skipping the guide for the frame is visually correct and self-heals on the next render.
Recommended Owner
@hediet — already the assignee of #244370, owner of the editor indent-guides / bracket-pair-guides area, and author of the line-height refactoring commits that shaped this rendering code.
The bundle file is available in the agent artifact in the workflow run linked above.
To create a pull request with the changes:
# Download the artifact from the workflow run
gh run download 30241462016 -n agent -D /tmp/agent-30241462016
# Fetch the bundle into a temporary ref, then update the local branch
git fetch /tmp/agent-30241462016/aw-microsoft-vscode-fix-indent-guides-null-visible-range-244370.bundle refs/heads/fix/indent-guides-null-visible-range-244370:refs/bundles/create-pr-fix-indent-guides-null-visible-range-244370-21c8e74b0a007704-5c845df9
git update-ref refs/heads/fix/indent-guides-null-visible-range-244370-21c8e74b0a007704 refs/bundles/create-pr-fix-indent-guides-null-visible-range-244370-21c8e74b0a007704-5c845df9
git checkout fix/indent-guides-null-visible-range-244370-21c8e74b0a007704
# Ensure the working tree matches the updated branch
git reset --hard
# Remove the temporary bundle ref
git update-ref -d refs/bundles/create-pr-fix-indent-guides-null-visible-range-244370-21c8e74b0a007704-5c845df9
# Push the branch to origin
git push https://github.com/bryanchen-d/vscode.git fix/indent-guides-null-visible-range-244370-21c8e74b0a007704
# Create the pull request
gh pr create --title 'fix: guard null visible range in indent guides prepareRender (fixes #244370)' --base main --head bryanchen-d:fix/indent-guides-null-visible-range-244370-21c8e74b0a007704 --repo microsoft/vscode
Summary
IndentGuidesOverlay.prepareRendercrashes withTypeError: Cannot read properties of null (reading 'left')atindentGuides.ts:138because it dereferences the result ofctx.visibleRangeForPosition(...)with a non-null assertion (!.left), while that method's declared contract isHorizontalPosition | null. When a guide's column has no visible range in the current frame (position not yet laid out, GPU/DOM viewline transition, or scroll/wrap edge), the method legitimately returnsnulland the!bypass throws. Notably, every sibling call tovisibleRangeForPositionin the same function already handlesnullsafely (?.left ?? 0on theleftOffsetat line 132, and?.left ?? (left + this._spaceWidth)for the horizontal-line width at lines 154-157) — only the vertical-guideleftcomputation used the unsafe!.Fixes #244370
Recommended reviewer:
@hedietCulprit Commit
The non-null assertion pattern predates the current telemetry window and lives in the editor indent-guides rendering path. The closest owning change is the line-height refactoring series by
@hediet(a9ab31d"Refactors: Reduces assumptions about line height." and its reapply5faa55a), which reworked how guide columns map to visible ranges. The exact introduction of the!could not be pinned down precisely because the working tree is a shallow clone (depth 1), sogit blamehistory is unavailable. The bug is a latent contract violation rather than a fresh regression.Code Flow
sequenceDiagram participant DOM as dom.ts scheduler participant ViewPart as view.ts participant Overlays as viewOverlays.ts participant Guides as indentGuides.ts prepareRender participant Ctx as RenderingContext DOM->>ViewPart: safeInvokeNoArg -> prepareRender ViewPart->>Overlays: prepareRender(ctx) Overlays->>Guides: prepareRender(ctx) Guides->>Ctx: visibleRangeForPosition(Position(line, guide.column)) Ctx-->>Guides: null (no visible range this frame) Note over Guides: null! .left -> TypeErrorAffected Files
src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts—prepareRenderguide loop: replaced the unsafe non-null assertion with a null check.Repro Steps
Not reliably reproducible on demand; it is a timing/layout-edge crash. It occurs when
prepareRenderruns for a guide whose column is not currently resolvable to a visible range — e.g. during rapid scrolling, viewline recycling, GPU renderer transitions, or wrapped-line layout churn while indent/bracket-pair guides are enabled. Telemetry shows real-world hits from the editor render loop (view.ts->viewOverlays.ts->indentGuides.ts).How the Fix Works
Chosen approach (
src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts): Theleftcomputation for a guide with a real model column (guide.column !== -1) previously didctx.visibleRangeForPosition(new Position(lineNumber, guide.column))!.left. The!is the type-system bypass: it asserts non-null on a value the method's signature declares asHorizontalPosition | null. This is fixed at the bypass site itself — not at a downstream reader and not by coercing to a benign default — by removing the assertion, checking the returned value, andcontinue-ing the guide loop when the range is absent so the guide is simply not emitted for this frame (it renders on the next frame once layout resolves). This matches the existing null-handling already used by every othervisibleRangeForPositioncall in the same function, so behavior is consistent and no error is masked:visibleRangeForPositionreturningnullis a legitimate, expected outcome of its contract, not invalid data produced upstream. There is no "producer of bad data" to fix — the producer already correctly returnsnull; the consumer's!was the defect.After this change,
indentGuides.ts:138cannot produce theTypeErrorbecause the code no longer dereferences the return value ofvisibleRangeForPositionwithout first confirming it is non-null; thecontinuepath skips the guide instead.Alternatives considered: Falling back to
leftOffset/0like line 132 was rejected because a guide whose column is not layout-resolvable would be painted at the wrong x-position (visual glitch) rather than omitted; skipping the guide for the frame is visually correct and self-heals on the next render.Recommended Owner
@hediet— already the assignee of #244370, owner of the editor indent-guides / bracket-pair-guides area, and author of the line-height refactoring commits that shaped this rendering code.Note
This was originally intended as a pull request, but the git push operation failed.
Original error: The process '/usr/bin/git' failed with exit code 128
Workflow Run: View run details and download bundle artifact
The bundle file is available in the
agentartifact in the workflow run linked above.To create a pull request with the changes: