Skip to content

fix: guard setDimensions against disposed ptyProcessReady (fixes #315282)#315284

Merged
vs-code-engineering[bot] merged 4 commits into
mainfrom
fix/terminal-setdimensions-disposed-guard-8d0f1a436b058723
May 19, 2026
Merged

fix: guard setDimensions against disposed ptyProcessReady (fixes #315282)#315284
vs-code-engineering[bot] merged 4 commits into
mainfrom
fix/terminal-setdimensions-disposed-guard-8d0f1a436b058723

Conversation

@vs-code-engineering
Copy link
Copy Markdown
Contributor

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

🔧 Error Fix

Summary

Error: Cannot read properties of undefined (reading 'then') in terminalProcessManager.ts:608

Fixes #315282
Recommended reviewer: @Tyriar

Culprit Commit

Field Value
Commit 363a5254
PR #314795
Author @bryanchen-d
Message Guard terminal resize/dispose race against xterm.js dimension getters

This PR added guards to terminalInstance.ts and terminalResizeDebouncer.ts for resize/dispose races, but missed guarding the downstream setDimensions call in terminalProcessManager.ts where ptyProcessReady can be undefined after disposal.

Code Flow

graph TD
    A["Configuration change fires during disposal"] --> B["setVisible()"]
    B --> C["_resize()"]
    C --> D["resizeDebouncer.resize()"]
    D --> E["_resizeBothCallback()"]
    E --> F["_updatePtyDimensions()"]
    F --> G["processManager.setDimensions(cols, rows, false)"]
    G --> H["this.ptyProcessReady.then() — CRASH: ptyProcessReady is undefined"]
Loading

Affected Files

  • src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts
  • src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Repro Steps

  1. Open a terminal in VS Code
  2. Trigger a command that disposes the terminal (e.g., close terminal action)
  3. If a configuration change event arrives simultaneously (race condition), setDimensions is called on the already-disposed process manager
  4. ptyProcessReady is undefined, calling .then() on it throws TypeError

How the Fix Works

Approach 2 (terminalInstance.ts, per @bryanchen-d's review): Dispose the _resizeDebouncer before _processManager.dispose() in terminalInstance.dispose(), so the resize callback chain is broken before ptyProcessReady gets nulled. This addresses the root cause (disposal ordering).

Recommended Owner

@Tyriar — primary terminal area owner, responsible for terminalProcessManager.ts

errors-fix-driver — cycle 13

Trigger: cron_changes_requested · Head: 7871d48508646356a4939c9b02d48220525c59cd (7871d48)

Item Action
Review thread on terminalProcessManager.ts:608 Addressed in cycle 2 (disposal ordering fix per @bryanchen-d's suggestion). Thread unresolved — awaiting reviewer action.
CI: Compile & Hygiene (failure) Pre-existing on main — unrelated to this PR's terminal changes.
Merge state blocked (CHANGES_REQUESTED review from @anthonykim1 outstanding)

Push: no — no code changes needed · Copilot rerequested: skipped (no push)

Ready gate: CHANGES_REQUESTED review from @anthonykim1 still outstanding → not marking ready.

errors-fix-driver — cycle 14

Trigger: cron_changes_requested · Head: 7871d48508646356a4939c9b02d48220525c59cd (7871d48)

Item Action
Review thread on terminalProcessManager.ts:608 Addressed in cycle 2 (disposal ordering fix per @bryanchen-d's suggestion). Thread unresolved — awaiting reviewer action.
CI: Compile & Hygiene (failure) Pre-existing on main — unrelated to this PR's terminal changes.
Merge state blocked (CHANGES_REQUESTED review from @anthonykim1 outstanding)

Push: no — no code changes needed · Copilot rerequested: skipped (no push)

Ready gate: CHANGES_REQUESTED review from @anthonykim1 still outstanding → not marking ready.

errors-fix-driver — cycle 15

Trigger: cron_changes_requested · Head: 7871d48508646356a4939c9b02d48220525c59cd (7871d48)

Item Action
Review thread on terminalProcessManager.ts:608 Addressed in cycle 2 (disposal ordering fix per @bryanchen-d's suggestion). Thread unresolved — awaiting reviewer action.
CI: Compile & Hygiene (failure) Pre-existing on main — unrelated to this PR's terminal changes.
CI: 24 other checks All passing ✅
Merge state blocked (CHANGES_REQUESTED review from @anthonykim1 outstanding)

Push: no — no code changes needed · Copilot rerequested: skipped (no push)

Ready gate: CHANGES_REQUESTED review from @anthonykim1 still outstanding → not marking ready. All actionable items have been addressed; awaiting human reviewer to dismiss CHANGES_REQUESTED or approve.

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

)

When a terminal process manager is disposed, ptyProcessReady is set to
undefined. If setDimensions is called after disposal (e.g., during a
resize triggered by a configuration change event that fires during the
dispose sequence), calling .then() on undefined throws a TypeError.

Add a guard clause to return early when ptyProcessReady is undefined,
preventing the crash without masking the error from telemetry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 15:16
@vs-code-engineering vs-code-engineering Bot requested review from Copilot and removed request for Copilot May 8, 2026 15:16
@vs-code-engineering vs-code-engineering Bot marked this pull request as ready for review May 8, 2026 15:17
@vs-code-engineering vs-code-engineering Bot requested review from Copilot and removed request for Copilot May 8, 2026 15:17
@bryanchen-d bryanchen-d requested review from anthonykim1 and Copilot May 8, 2026 15:18
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.

Pull request overview

Fixes a terminal resize/dispose race in the workbench terminal process manager by preventing setDimensions from calling .then() on a disposed/cleared ptyProcessReady promise reference.

Changes:

  • Add an early-return guard in TerminalProcessManager.setDimensions when ptyProcessReady has been cleared during disposal, avoiding a Cannot read properties of undefined (reading 'then') crash.
Show a summary per file
File Description
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts Add guard in setDimensions to safely no-op when ptyProcessReady is unset during disposal.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

Comment thread src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts Outdated
Dispose _resizeDebouncer before _processManager.dispose() so that no
resize callbacks can fire after ptyProcessReady has been nulled. This
addresses the root cause (disposal ordering) rather than just guarding
against the symptom, as suggested by @bryanchen-d.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-code-engineering vs-code-engineering Bot enabled auto-merge (squash) May 13, 2026 17:33
Make the setDimensions guard conditional on _store.isDisposed so it
only silences the legitimate teardown race (#315282). Calls against a
live but uninitialized manager now throw an explicit error instead of
being silently dropped, preserving our ability to surface real caller
ordering bugs.
@bryanchen-d
Copy link
Copy Markdown
Contributor

bryanchen-d commented May 14, 2026

4 production trigger paths (Kusto, last 14d)

Pulled from RawEventsVSCode matching the Cannot read properties of undefined (reading 'then') stack at terminalProcessManager.setDimensions:

# Trigger Hits Stack head
1 Editor-area terminal closed → xterm dispose → WebGL renderer dispose fires _onDidRequestRefreshDimensions synchronously → layout → _resize_updatePtyDimensionssetDimensions 986 _disposeOfWebglRenderer_onDidRequestRefreshDimensions.fire
2 Trash-icon close + LSP / config change cascade re-entering layout during dispose 859 closeTerminal → cascade through _languageFeaturesService
3 _onWillShutdown (reload window with terminal open) 214 shutdown handler → terminal dispose
4 Kill All / Kill from menu (_runForSelectionOrInstance) 904 command path → mass dispose

All four reach the same line: return this.ptyProcessReady.then(...) after ptyProcessReady has been nulled by the toDisposable registered in the manager's constructor. Path #1 needs no extension involvement — purely first-party code, fully natural repro (move terminal to editor area + close the tab).

Why the conditional guard is safe

The previous version of this guard was unconditional:

if (!this.ptyProcessReady) { return Promise.resolve(); }

That had the legitimate concern of hiding caller-side ordering bugs — e.g. if anything ever called setDimensions on a freshly constructed manager before createProcess completes, we'd silently swallow it.

The refined guard splits the two cases:

if (this._store.isDisposed) {
    return Promise.resolve();   // legitimate teardown race (#315282)
}
if (!this.ptyProcessReady) {
    throw new Error('TerminalProcessManager.setDimensions called before initialization');
}

DisposableStore.dispose() flips _isDisposed = true before iterating registered disposables, so by the time the toDisposable callback nulls ptyProcessReady, this._store.isDisposed is already true. That makes the disposed-vs-uninitialized distinction reliable.

Net effect:

  • Post-dispose re-entrant resize during the synchronous teardown stack → silent no-op (intended; matches "resize on a dead pty" semantics).
  • Pre-init call on a live manager → loud, explicit Error reaches errorTelemetry, so the underlying ordering bug stays visible.
  • Combined with @bryanchen-d's reorder of _resizeDebouncer.dispose() before _processManager.dispose(), the resize-debouncer entry path (the most frequent contributor to path Open Source VS Code #1) is also eliminated at the root, leaving the guard purely as defense in depth for the other three paths.

…sions-disposed-guard-8d0f1a436b058723

# Conflicts:
#	src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
@bryanchen-d bryanchen-d requested a review from anthonykim1 May 19, 2026 04:10
@vs-code-engineering vs-code-engineering Bot merged commit dff2ee2 into main May 19, 2026
25 checks passed
@vs-code-engineering vs-code-engineering Bot deleted the fix/terminal-setdimensions-disposed-guard-8d0f1a436b058723 branch May 19, 2026 06:01
@vs-code-engineering vs-code-engineering Bot added this to the 1.122.0 milestone May 19, 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.

[Regression] Cannot read properties of undefined (reading 'then') — terminalProcessManager.setDimensions

4 participants