Copilot Chat: “InstantiationService has been disposed” thrown from PromptRenderer.render during long sessions
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
### Type of issue
Bug
### Steps to Reproduce
1. Keep a Copilot Chat session open for hours with heavy message churn (many tool calls per turn, long agent loops, large context).
2. Continue driving turns; interrupt/cancel some mid-flight; open/close chat windows.
3. After enough churn, the render pipeline throws `InstantiationService has been disposed` and the extension host crashes.
Recurred ~10× in one evening on the same install; same stack signature each time.
### Actual Behavior
Extension host crash. Session becomes unusable until VS Code (or the extension host) is restarted.
### Expected Behavior
No crash. Cancellation or parent-service dispose during an in-flight render should short-circuit cleanly or surface as a cancellation error to the caller — not escape from `InstantiationService._throwIfDisposed` and take down the render pipeline.
### Stack signature
Error: InstantiationService has been disposed
at ._throwIfDisposed (.../copilot/dist/extension.js)
...
at async .render (.../copilot/dist/extension.js)
Identical `_throwIfDisposed → async .render` shape on every recurrence.
### Environment
- OS: macOS
- VS Code: 1.136.1 (Universal)
- GitHub Copilot Chat: 1.0.81-0
### Diagnostic pointer
The vendored `InstantiationService` at [extensions/copilot/src/util/vs/platform/instantiation/common/instantiationService.ts](https://github.com/microsoft/vscode/blob/main/extensions/copilot/src/util/vs/platform/instantiation/common/instantiationService.ts) throws from `_throwIfDisposed` on `createChild` / `createInstance` / `invokeFunction`. The most plausible async `.render` site in that bundle is [`PromptRenderer.render`](https://github.com/microsoft/vscode/blob/main/extensions/copilot/src/extension/prompts/node/base/promptRenderer.ts), which:
- creates `hydratedInstaService = instantiationService.createChild(...)` per render,
- awaits `super.render(progress, token)` — an async tree walk from `@vscode/prompt-tsx` that keeps calling `createElement` → `_instantiationService.createInstance(...)` between awaits,
- calls `this._instantiationService.dispose()` at the end (**not** in a `finally`).
Two candidate races consistent with the stack:
1. Parent `InstantiationService` disposes while `super.render` is still walking → the hydrated child is cascade-disposed → the next `createElement` throws.
2. `renderer.render(...)` returns and disposes the child; a subsequent use of the same renderer (e.g. `countTokens()`, or a retained reference) touches the disposed service.
Additionally, `super.render` throwing skips the trailing `this._instantiationService.dispose()` — the hydrated child leaks (addressed by an accompanying PR).
### Related
- Same error class, sibling site fixed in settings editor: #330277 / #330344 (principle: guard at the async re-entry boundary in the owning object, not inside `InstantiationService`).
- Closest open shape-match for chat: #333132.
- Recent unrelated site fixed: #333537 / #333540.
### Workaround
"Developer: Restart Extension Host" clears the state; the crash re-emerges under heavy load.
Contributor guide
Assessment
This issue has not been assessed yet.