Before submitting
Area
apps/desktop
Steps to reproduce
This is the exact observed sequence that produced two stale process trees. It has not yet been reduced to a deterministic minimal reproduction.
The preceding update and PowerToys Run are observed context; neither is confirmed as a requirement.
- Run T3 Code Nightly on Windows.
- Install an available in-app update and allow the application to close/relaunch.
- While no application window is visible, launch T3 Code Nightly through PowerToys Run.
- Launch it again approximately 30 seconds later.
- Allow a subsequent launch to become the normal visible instance.
- Inspect all
T3 Code (Nightly).exe processes using Task Manager, Process Explorer, or Win32_Process.
- Observe whether the earlier launch trees exit.
Observed timeline:
- Update installation started at
2026-07-22 14:14:09.631 -05:00.
- First later launch started at
14:18:58.027.
- Second later launch started at
14:19:28.614.
- A successful startup trace began at
14:20:40.533.
- Both earlier process trees were still alive at
2026-07-23 14:56:07 -05:00, more than 24 hours later.
Expected behavior
A secondary process that does not become the single-instance lock owner should notify/reveal the primary instance and terminate promptly.
The rejected process should not leave behind an Electron main process, GPU process, network-service process, window, backend, renderer, or listening socket.
Normal graceful-shutdown handling for the primary application should not prevent a secondary instance from exiting.
Actual behavior
Two earlier launch attempts remained alive as separate headless Electron process trees for more than 24 hours.
Each tree contained:
- One Electron main process
- One GPU process
- One network-service utility process
Neither tree contained:
- A renderer process
- An embedded T3 backend process
- A visible window or window handle
- A TCP listener owned by any process in the tree
At the latest snapshot, they consumed approximately 325.4 MiB combined.
The process shape and source ordering are consistent with secondary instances reaching the single-instance rejection path and failing to terminate. However, current telemetry does not record the lock result or PID, so this remains the leading hypothesis rather than a confirmed fact.
Suspected lifecycle race
At the affected commit:
DesktopApp.startup performs shell-environment discovery and registers normal lifecycle handling before requesting the single-instance lock.
DesktopClerk.configure requests the lock. If rejected, it calls app.quit() and immediately interrupts the Effect startup fiber.
- The already-registered
before-quit handler prevents that first quit, requests graceful shutdown, waits for DesktopShutdown.awaitComplete, and schedules a second app.quit().
- Shutdown completion depends on the scoped application finalizer, while the rejected startup path is interrupting and unwinding that scope.
The suspected race is between startup interruption/scope teardown, shutdown completion, and the asynchronous second quit.
The persistent processes suggest either that shutdown completion is not observed in this partial-startup state or that the second quit does not execute successfully. Instrumentation is needed to distinguish those paths.
Suggested investigation
- Log PID, parent PID, lock accepted/rejected, and time spent before requesting the lock.
- Log entry and completion of
before-quit, shutdown completion, the second quit, will-quit, and final process exit.
- Consider acquiring the lock immediately after resolving and setting the user-data path, before shell discovery and normal lifecycle registration.
- Give rejected secondary instances a minimal termination path that is not intercepted by primary-instance graceful shutdown.
- Add a Windows regression test that starts one lock owner and multiple concurrent secondaries, then verifies that every losing process tree exits within a bounded timeout.
Related but not duplicate
- #1460: Windows NSIS updates could not proceed while application windows remained alive.
- #4328: Windows shows no progress during a long silent update.
- #3553: a live Windows backend could incorrectly enter reconnecting state.
- #2359: analogous leaked-process cleanup for temporary OpenCode servers.
- #2424: open PR modifying
second-instance handling for deep links, but not rejected-instance cleanup.
This report is intentionally limited to the process leak. It does not claim that these stale trees cause the separate reconnect delay.
Impact
Minor bug or occasional failure
This was observed once, but two launches produced two process trees that survived for more than 24 hours and retained approximately 325 MiB. The severity should be reconsidered if controlled testing shows it happens consistently during updates or concurrent launches.
Version or commit
T3 Code Nightly 0.0.29-nightly.20260722.878 @ 9a0a07167f0623c3a7db0ffeff2e3939760309df
Release tag: v0.0.29-nightly.20260722.878
Environment
- Windows x64, build
26200.8875
- Timezone:
America/Bogota, UTC-05:00
- Electron
41.5.0
- Executable:
%LOCALAPPDATA%\Programs\t3-code-desktop\T3 Code (Nightly).exe
- User-data directory in child arguments:
%APPDATA%\t3code
- Observed launcher: PowerToys Run
- Launcher process:
PowerToys.PowerLauncher.exe, PID 17728
Logs or stack traces
Process snapshot:
2026-07-23 14:56:07.636 -05:00
PowerToys.PowerLauncher.exe
PID 17728
Started 2026-07-21 17:01:32.039 -05:00
│
├─ T3 Code (Nightly).exe
│ PID 29556
│ Started 2026-07-22 14:18:58.027 -05:00
│ MainWindowHandle=0
│ WorkingSet=57.4 MiB
│
│ ├─ PID 5660
│ │ Started 2026-07-22 14:19:25.071 -05:00
│ │ --type=gpu-process
│ │ WorkingSet=51.5 MiB
│ │
│ └─ PID 35060
│ Started 2026-07-22 14:19:25.092 -05:00
│ --type=utility
│ --utility-sub-type=network.mojom.NetworkService
│ WorkingSet=43.4 MiB
│
│ Tree total: approximately 152.3 MiB
│
└─ T3 Code (Nightly).exe
PID 23264
Started 2026-07-22 14:19:28.614 -05:00
MainWindowHandle=0
WorkingSet=64.4 MiB
├─ PID 35752
│ Started 2026-07-22 14:19:53.366 -05:00
│ --type=gpu-process
│ WorkingSet=59.2 MiB
│
└─ PID 25728
Started 2026-07-22 14:19:53.384 -05:00
--type=utility
--utility-sub-type=network.mojom.NetworkService
WorkingSet=49.5 MiB
Tree total: approximately 173.1 MiB
Combined working set: approximately 325.4 MiB
No TCP rows were returned by `netstat -ano -p tcp` for:
29556, 5660, 35060, 23264, 35752, or 25728.
A healthy visible instance had renderer children and an embedded
`apps/server/dist/bin.mjs --bootstrap-fd 3` backend child.
Neither stale tree contained those process types.
Relevant update trace from %USERPROFILE%\.t3\userdata\logs\desktop.trace.ndjson.4:
traceId=3e87348ea1cf0f7487cd3ddbb9219503
2026-07-22 14:14:09.631 -05:00
desktop.updates.installDownloadedUpdate
duration=2918.812 ms
status=Success
2026-07-22 14:14:09.631 -05:00
desktop.updates.install
duration=2919.026 ms
status=Success
2026-07-22 14:14:10.279 -05:00
desktop.lifecycle.windowAllClosed
duration=0.235 ms
status=Success
A separate successful startup trace confirms the startup ordering. It cannot be correlated to either stale PID because current trace records do not include the process PID:
traceId=7f5ac4dcb7a82c8ef0d6a4089a78715c
runId=2d7ccd59aca8
startup=2026-07-22 14:20:40.533 -05:00
desktop.shellEnvironment.installIntoProcess 7179.908 ms
├─ first Windows environment read 2584.700 ms
└─ second Windows environment read 4593.264 ms
desktop.appIdentity.resolveUserDataPath 1.514 ms
desktop.appIdentity.configure 1.957 ms
desktop.lifecycle.register 5.057 ms
desktop.clerk.configure 2.586 ms
desktop.electron.whenReady 0.253 ms
Current telemetry does not explicitly record:
- Startup PID and parent PID
- Single-instance lock accepted/rejected
- Entry into the rejected-instance exit path
- Whether DesktopShutdown.awaitComplete resolved
- Whether the second app.quit() executed
- Final will-quit or process-exit completion
Screenshots, recordings, or supporting files
The relevant sanitized process and trace excerpts are included above.
The complete trace is not attached because it contains unrelated local paths and endpoint information. A redacted Process Explorer screenshot or process snapshot can be added if needed.
Workaround
Restarting Windows removes the stale process trees.
They can also be removed manually by ending only the verified headless root trees in Process Explorer or Task Manager. PIDs must be rechecked first to avoid terminating the active application instance.
No prevention is currently known other than avoiding repeated launches while an update or relaunch appears to still be in progress.
Before submitting
Area
apps/desktop
Steps to reproduce
This is the exact observed sequence that produced two stale process trees. It has not yet been reduced to a deterministic minimal reproduction.
The preceding update and PowerToys Run are observed context; neither is confirmed as a requirement.
T3 Code (Nightly).exeprocesses using Task Manager, Process Explorer, orWin32_Process.Observed timeline:
2026-07-22 14:14:09.631 -05:00.14:18:58.027.14:19:28.614.14:20:40.533.2026-07-23 14:56:07 -05:00, more than 24 hours later.Expected behavior
A secondary process that does not become the single-instance lock owner should notify/reveal the primary instance and terminate promptly.
The rejected process should not leave behind an Electron main process, GPU process, network-service process, window, backend, renderer, or listening socket.
Normal graceful-shutdown handling for the primary application should not prevent a secondary instance from exiting.
Actual behavior
Two earlier launch attempts remained alive as separate headless Electron process trees for more than 24 hours.
Each tree contained:
Neither tree contained:
At the latest snapshot, they consumed approximately
325.4 MiBcombined.The process shape and source ordering are consistent with secondary instances reaching the single-instance rejection path and failing to terminate. However, current telemetry does not record the lock result or PID, so this remains the leading hypothesis rather than a confirmed fact.
Suspected lifecycle race
At the affected commit:
DesktopApp.startupperforms shell-environment discovery and registers normal lifecycle handling before requesting the single-instance lock.DesktopClerk.configurerequests the lock. If rejected, it callsapp.quit()and immediately interrupts the Effect startup fiber.before-quithandler prevents that first quit, requests graceful shutdown, waits forDesktopShutdown.awaitComplete, and schedules a secondapp.quit().The suspected race is between startup interruption/scope teardown, shutdown completion, and the asynchronous second quit.
The persistent processes suggest either that shutdown completion is not observed in this partial-startup state or that the second quit does not execute successfully. Instrumentation is needed to distinguish those paths.
Suggested investigation
before-quit, shutdown completion, the second quit,will-quit, and final process exit.Related but not duplicate
second-instancehandling for deep links, but not rejected-instance cleanup.This report is intentionally limited to the process leak. It does not claim that these stale trees cause the separate reconnect delay.
Impact
Minor bug or occasional failure
This was observed once, but two launches produced two process trees that survived for more than 24 hours and retained approximately 325 MiB. The severity should be reconsidered if controlled testing shows it happens consistently during updates or concurrent launches.
Version or commit
T3 Code Nightly 0.0.29-nightly.20260722.878 @ 9a0a07167f0623c3a7db0ffeff2e3939760309dfRelease tag:
v0.0.29-nightly.20260722.878Environment
26200.8875America/Bogota, UTC-05:0041.5.0%LOCALAPPDATA%\Programs\t3-code-desktop\T3 Code (Nightly).exe%APPDATA%\t3codePowerToys.PowerLauncher.exe, PID17728Logs or stack traces
Process snapshot: 2026-07-23 14:56:07.636 -05:00 PowerToys.PowerLauncher.exe PID 17728 Started 2026-07-21 17:01:32.039 -05:00 │ ├─ T3 Code (Nightly).exe │ PID 29556 │ Started 2026-07-22 14:18:58.027 -05:00 │ MainWindowHandle=0 │ WorkingSet=57.4 MiB │ │ ├─ PID 5660 │ │ Started 2026-07-22 14:19:25.071 -05:00 │ │ --type=gpu-process │ │ WorkingSet=51.5 MiB │ │ │ └─ PID 35060 │ Started 2026-07-22 14:19:25.092 -05:00 │ --type=utility │ --utility-sub-type=network.mojom.NetworkService │ WorkingSet=43.4 MiB │ │ Tree total: approximately 152.3 MiB │ └─ T3 Code (Nightly).exe PID 23264 Started 2026-07-22 14:19:28.614 -05:00 MainWindowHandle=0 WorkingSet=64.4 MiB ├─ PID 35752 │ Started 2026-07-22 14:19:53.366 -05:00 │ --type=gpu-process │ WorkingSet=59.2 MiB │ └─ PID 25728 Started 2026-07-22 14:19:53.384 -05:00 --type=utility --utility-sub-type=network.mojom.NetworkService WorkingSet=49.5 MiB Tree total: approximately 173.1 MiB Combined working set: approximately 325.4 MiB No TCP rows were returned by `netstat -ano -p tcp` for: 29556, 5660, 35060, 23264, 35752, or 25728. A healthy visible instance had renderer children and an embedded `apps/server/dist/bin.mjs --bootstrap-fd 3` backend child. Neither stale tree contained those process types.Relevant update trace from
%USERPROFILE%\.t3\userdata\logs\desktop.trace.ndjson.4:A separate successful startup trace confirms the startup ordering. It cannot be correlated to either stale PID because current trace records do not include the process PID:
Current telemetry does not explicitly record:
Screenshots, recordings, or supporting files
The relevant sanitized process and trace excerpts are included above.
The complete trace is not attached because it contains unrelated local paths and endpoint information. A redacted Process Explorer screenshot or process snapshot can be added if needed.
Workaround
Restarting Windows removes the stale process trees.
They can also be removed manually by ending only the verified headless root trees in Process Explorer or Task Manager. PIDs must be rechecked first to avoid terminating the active application instance.
No prevention is currently known other than avoiding repeated launches while an update or relaunch appears to still be in progress.