VS Code window killed by macOS (killed, code 9) when Copilot Agent edits .json5 files
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
## Summary
In a multi-folder workspace, when using Copilot Agent to edit code and the Agent's editing scope involves a `.json5` file (e.g. `buildinfo.json5`), the VS Code window is forcibly terminated by the macOS kernel after approximately 20 seconds, with the error message "The window terminated unexpectedly (reason: 'killed', code: '9')".
Once this issue first occurs, every subsequent Agent prompt in the workspace reliably triggers the crash. Restarting VS Code does not resolve it. I have recorded 7 crashes across 2 log sessions, all following an identical error pattern.
## Log Collection Script & Captured Logs
### Log collection script
```bash
#!/bin/bash
# collect_crash_logs.sh — Collect VS Code crash-related logs
# Usage: ./collect_crash_logs.sh [log session directory name]
LOG_BASE="$HOME/Library/Application Support/Code/logs"
SESSION="${1:-$(ls -t "$LOG_BASE" | head -1)}"
SESSION_DIR="$LOG_BASE/$SESSION"
echo "=== Log session: $SESSION ==="
# 1. main.log — crash records
echo "========== main.log (crash records) =========="
cat "$SESSION_DIR/main.log" 2>/dev/null | grep -i "kill\|crash\|renderer.*gone"
# 2. Per-window exthost.log — changeLanguage error stats
for w in "$SESSION_DIR"/window*; do
WNAME=$(basename "$w")
ERR_COUNT=$(cat "$w/exthost/exthost.log" 2>/dev/null | grep -c "changeLanguage")
if [ "$ERR_COUNT" -gt 0 ]; then
echo ""
echo "========== $WNAME/exthost.log =========="
echo "changeLanguage error count: $ERR_COUNT"
echo ""
echo "--- First error ---"
cat "$w/exthost/exthost.log" 2>/dev/null | grep -B1 "changeLanguage" | head -4
echo ""
echo "--- Last error ---"
cat "$w/exthost/exthost.log" 2>/dev/null | grep -B1 "changeLanguage" | tail -4
echo ""
echo "--- Non-changeLanguage errors ---"
cat "$w/exthost/exthost.log" 2>/dev/null | grep -E "^\d{4}" | grep -v "changeLanguage" | grep -v "NOT found" | head -10
fi
done
# 3. renderer.log — "unexpected error" time range
echo ""
echo "========== renderer.log =========="
for w in "$SESSION_DIR"/window*; do
WNAME=$(basename "$w")
ERR_COUNT=$(cat "$w/renderer.log" 2>/dev/null | grep -c "出现未知错误\|An unexpected error")
if [ "$ERR_COUNT" -gt 0 ]; then
echo "--- $WNAME ---"
echo "Unexpected error count: $ERR_COUNT"
cat "$w/renderer.log" 2>/dev/null | grep "出现未知错误\|An unexpected error" | head -1
cat "$w/renderer.log" 2>/dev/null | grep "出现未知错误\|An unexpected error" | tail -1
fi
done
```
### Captured logs (sanitized)
**main.log — crash records:**
```
2026-09-18 15:57:43.401 [error] CodeWindow: renderer process gone (reason: killed, code: 9)
2026-09-18 16:19:49.526 [error] CodeWindow: renderer process gone (reason: killed, code: 9)
```
**exthost.log — changeLanguage errors (7 crashes summary):**
| Crash | Window | Timestamp | changeLanguage errors |
|-------|--------|-----------|---------------------|
| 1 | window4 | 14:15:09 | 2,768 |
| 2 | window5 | 15:32:41 | 4,506 |
| 3 | window6 | 15:36:35 | 4,554 |
| 4 | window7 | — | 2,442 |
| 5 | window1 | 15:41:46 | 2,869 |
| 6 | window1 | 15:57:43 | 2,386 |
| 7 | window3 | 16:19:49 | 1,681 |
**exthost.log — error sample (sanitized paths):**
```
2026-09-18 16:19:47.674 [error] Error: document 'chat-editing-snapshot-text-model:
///entry/src/main/resources/rawfile/buildinfo.json5
?{"session":{"$mid":1,"external":"vscode-chat-session://local/",
"path":"/","scheme":"vscode-chat-session","authority":"local"},
"requestId":"request_","undoStop":"__epoch_22",
"scheme":"file","authority":""}' NOT found
at XP.changeLanguage (extensionHostProcess.js:667:7776)
2026-09-18 16:19:47.676 [error] Error: document 'chat-editing-snapshot-text-model:
///entry/src/main/resources/rawfile/buildinfo.json5?{...}' NOT found
at XP.changeLanguage (extensionHostProcess.js:667:7776)
... (repeats 1,681 times in ~2 seconds)
```
**exthost.log — non-changeLanguage errors:**
```
2026-09-18 16:19:48.369 [info] Extension host terminating: renderer closed the MessagePort
2026-09-18 16:19:48.613 [error] An error occurred when disposing the subscriptions
for extension 'NailyZero.vscode-naily-ets':
2026-09-18 16:19:48.613 [error] AggregateError: Encountered errors while disposing of store
2026-09-18 16:19:48.667 [error] Error: Channel has been closed
```
**renderer.log — 20 seconds before crash:**
```
2026-09-18 16:19:28.323 [error] An unexpected error occurred. See logs for details.
2026-09-18 16:19:29.323 [error] An unexpected error occurred. See logs for details.
2026-09-18 16:19:30.345 [error] An unexpected error occurred. See logs for details.
... (once per second for ~20 seconds)
2026-09-18 16:19:47.456 [error] An unexpected error occurred. See logs for details.
```
**renderer.log — other logs before crash:**
```
2026-09-18 16:19:14.163 [info] Extension host (LocalProcess pid: 71977) is unresponsive.
2026-09-18 16:19:14.957 [info] UNRESPONSIVE extension host: starting to profile NOW
2026-09-18 16:19:14.957 [info] Extension host (LocalProcess pid: 71977) is responsive.
2026-09-18 16:19:15.010 [warning] UNRESPONSIVE extension host: 'vscode.json-language-features'
took 22.96% of 0.276ms
```
**Per-second error burst frequency (crash #7):**
```
16:19:47 → 421 errors/sec (burst begins)
16:19:48 → 1,196 errors/sec (peak, Extension host begins terminating)
16:19:49 → 68 errors/sec (process SIGKILLed)
```
**Key evidence — all errors point to the same request:**
```
requestId: request_ (all identical)
undoStop: __epoch_22 (all identical)
file: buildinfo.json5 (only file involved)
```
## AI Root Cause Analysis
The crash is caused by an infinite loop triggered by a race condition between `chat-editing-snapshot` and `changeLanguage`.
**Mechanism:**
1. Copilot Agent initiates an edit on a `.json5` file in the workspace
2. The `chat-editing-snapshot-text-model` mechanism creates a snapshot document for the file
3. The snapshot document is immediately disposed (or not properly registered in the document registry)
4. `XP.changeLanguage` attempts to switch the language mode on the snapshot document (`.json5` → JSON)
5. Since the document no longer exists, it throws a `"document '...' NOT found"` error
6. The caller catches the error and immediately retries, forming an infinite loop
7. ~1,600–4,500 identical errors accumulate in ~2 seconds, causing memory to spike
8. macOS jetsam detects memory pressure and sends SIGKILL (signal 9)
**Key evidence:**
- All 7 crashes follow an identical error pattern, all targeting `.json5` files
- Within a single crash, all errors share the same `requestId` and `undoStop`, confirming a single edit request triggers the entire infinite retry
- Error frequency rapidly escalates from 421/sec to 1,196/sec, consistent with an infinite loop
- `.json5` files are handled by the `vscode.json-language-features` built-in extension; `changeLanguage` attempts to switch the `.json5` language mode to JSON, and this switching path has a race condition on snapshot documents
**Distinction from existing fixed issues:**
- **#326913**: Same SIGKILL symptom, but root cause is Mach port exhaustion, not a `changeLanguage` loop
- **#296064**: Parent issue for chat editing crashes; PR #336095 fixed renderer-freeze but does not cover this path
- **#324549**: Chat editing checkpoint crash via a different code path (`pieceTreeTextBuffer`)
- **PR #331840**: Prevents agent from editing snapshot copies, but does not address the `changeLanguage` retry loop
## Suggested Fix Directions
1. **Precondition check**: Before calling `XP.changeLanguage`, check whether the target document still exists in the document registry. If it does not exist, skip the operation to avoid executing actions on disposed documents.
2. **Error handling termination**: When `changeLanguage` throws a `"document NOT found"` error, the retry should terminate rather than continue looping. The current retry logic lacks judgment for this type of unrecoverable error, treating a permanent error (document does not exist) as a transient one.
3. **Retry limit / circuit breaker**: Add a maximum retry count or circuit breaker to the retry logic for `changeLanguage`, so that even if an unexpected loop occurs, it can be interrupted before errors accumulate to dangerous levels, preventing memory spikes from causing the process to be killed.
4. **Fix snapshot document lifecycle**: Investigate why the snapshot document created by `chat-editing-snapshot-text-model` is disposed before `changeLanguage` executes, and ensure the snapshot document's lifecycle covers all operations performed on it.
Contributor guide
Research direction
Start at XP.changeLanguage in extensionHostProcess.js and trace the vscode.json-language-features path for chat-editing-snapshot-text-model documents. Reproduce the .json5 Copilot Agent edit and inspect the repeated changeLanguage errors around the shared requestId and undoStop. Done means the disposed-document path no longer produces an unbounded error burst or kills the VS Code window.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, typescript, vscode
- Domain
- desktop, devtools, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100