[Bug]: Windows desktop typing lags even in empty chats; browser interface is smooth#12689

openedSep 20, 2026byHhnasser22

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. Open T3 Code Desktop on Windows.
  2. Start a new, empty chat.
  3. Type continuously in the composer and observe input lag.
  4. Keep the same local backend running and open http://localhost:3773 in a browser.
  5. Type in the browser interface. Typing is smooth there.

This reproduces on my installation; I have not tested with a fresh application profile.

Expected behavior

Typing in the desktop composer should appear immediately, with responsiveness comparable to the browser interface.

Actual behavior

Typing in the desktop application visibly lags, including in new, empty chats. The browser interface connected to the same backend does not lag.

The desktop also displays “Some requests are slow” messages, although I have not established whether those warnings share the same cause.

Impact

Blocks work completely

Version or commit

0.0.42

Environment

Windows 11 Pro, build 26200, T3 Code Desktop (Alpha) 0.0.42, Intel Core i7-12700H, 20 logical processors 64 GB RAM Intel Iris Xe / NVIDIA GeForce RTX 3070 Ti Laptop GPU Local backend; browser interface on the same machine is responsive

Logs or stack traces

shell
1Renderer CPU profile captured while typing:
2
3Recording duration: 18.3 seconds
4Renderer idle time: approximately 15.9 seconds (87%)
5One continuous approximately 1,000 ms interval in:
6
7getLocalEnvironmentBootstraps
8 -> ipcRenderer.sendSync
9 -> native sendSync
10
11Installed preload implementation:
12electron.ipcRenderer.sendSync(GET_LOCAL_ENVIRONMENT_BOOTSTRAPS_CHANNEL)
13
14The installed frontend polls environment topology every 3 seconds.
15Desktop traces during the capture show bootstrap handler execution
16around 0.06–0.18 ms.
17
18This suggests a synchronous desktop IPC stall. The source of the one-second wait is not established, and the profile alone does not prove that this accounts for all perceived input lag.

Screenshots, recordings, or supporting files

cpu-profile.zip

Workaround

Use the browser interface at http://localhost:3773 while the local backend remains running. Typing is smooth there. No application settings or binaries were changed.

Triage

Thanks for the profile and the browser-vs-desktop comparison — that is enough to treat this as a real Windows desktop input-lag bug.

What we think is going on

The desktop renderer periodically reads environment topology over synchronous IPC. getLocalEnvironmentBootstraps() in the preload is ipcRenderer.sendSync(...). Electron blocks the entire renderer until the main process replies, so keystrokes cannot paint during that wait.

The installed frontend matches the profile:

  • Connection platform polls topology every 3 seconds (PLATFORM_POLL_INTERVAL in apps/web/src/connection/platform.ts) because the bridge has no change event.
  • That poll reads the primary target and the secondary bootstrap list. Both call window.desktopBridge.getLocalEnvironmentBootstraps().
  • The same poll also hits getLocalEnvironmentEnabled() via sendSync.
  • The command palette / legacy sidebar can add a second 2s poll (useDesktopLocalBootstraps).

The browser UI at http://localhost:3773 does not have desktopBridge, so it never takes this path. Smooth typing there with the same backend is expected.

Your capture also matches the code: desktop traces of the bootstrap handler are sub-millisecond (apps/desktop/src/ipc/methods/window.ts), while the renderer spent ~1s inside native sendSync. That points at IPC transport / main-process contention, not a slow handler. One 1s stall does not prove this is the only source of perceived lag, but it is a sufficient explanation for visible freezes while typing.

The “Some requests are slow” toast is a separate 15s RPC-ack warning (SlowRpcRequestToastCoordinator). A 1s IPC stall would not trip it by itself. Leaving that as an unconfirmed overlapping symptom.

Likely code

  • apps/desktop/src/preload.ts (getLocalEnvironmentBootstraps → sendSync)
  • apps/desktop/src/ipc/methods/window.ts + apps/desktop/src/ipc/DesktopIpc.ts (handleSync)
  • apps/web/src/connection/platform.ts (3s poll)
  • apps/web/src/connection/desktopLocal.ts
  • apps/web/src/environments/primary/target.ts
  • apps/web/src/connection/useDesktopLocalBootstraps.ts

This shape landed with the parallel local/WSL backend work (#2751). No duplicate issue found. Related but not the same: #6248 (Windows main-thread blocking), #11771 (remove the slow-request toast), #11754 (@ picker typing jank).

Next step

Stop polling this snapshot over sendSync. Preferred fix is a main→renderer topology change event, or async invoke plus a cached last-known snapshot so the UI thread never blocks. After that, re-profile empty-chat typing on Windows. Investigating the ~1s transport wait is useful follow-up, but removing sendSync from the hot poll is the first change.

Accepting as a Windows desktop performance bug. Browser workaround stands until a desktop build lands.

Synced from GitHub

I’m seeing what looks like the same bug on Windows 11 / T3 Desktop 0.0.42, but with much more severe stalls: the whole T3 window goes “Not Responding” for ~15–30 seconds while every other application remains completely responsive.

A few useful observations from my reproduction:

  • Happens even in new/small threads.
  • Reproduced with zero agents running.
  • Also happened while T3 was unfocused.
  • No reconnect / connection failure UI.
  • The remote Linux T3 server remains responsive and continues doing work during the desktop freeze.

I correlated several freezes with desktop.trace.ndjson. Normally the topology IPC runs about every 3.002s, but during observed freezes I got gaps of ~16.7s, ~30.7s, and ~18.7s before polling resumed.

The interesting part is that desktop:get-local-environment-enabled / desktop:get-local-environment-bootstraps themselves still complete in roughly 0.06–0.48ms once dispatched.

Example:

text
123:33:09.414 topology IPC
223:33:09.415 topology IPC
3
4--- T3 window frozen / Not Responding ---
5
623:33:40.151 topology IPC
723:33:40.154 topology IPC
823:33:43.162 normal ~3s cadence resumes

So there’s a 30.736s hole while the actual IPC handlers remain sub-ms.

This seems strongly consistent with the ipcRenderer.sendSync / IPC transport or main-process contention described in the triage above, and makes #12698 look very relevant. I haven’t captured a renderer profile during one of the long freezes yet, so I can’t prove the entire 30s is spent inside sendSync, but this appears to be an independent and more severe reproduction of the same failure mode.

Synced from GitHub

Reproduced with a renderer CPU profile and trace on the latest nightly, 0.0.46-nightly.20261010.2935 (98beed1a226c, Electron 44.4.5, Chrome 152).

Environment: Windows 11 Pro 10.0.26200, x64, RTX 5070, 200 Hz display, Desktop app with a local backend. Only the T3 window stutters; the rest of the system stays smooth.

Capture: a 30 s DevTools trace and CPU profile of the main renderer (--remote-debugging-port), taken while the stutter was happening, with 796 keystrokes.

  • The worst main-thread tasks were 339 ms and 162 ms, almost entirely ElectronApiIPC::MessageSync (298 ms and 159 ms).
  • 30 sync IPC calls took 510 ms in total. The median call was 0.43 ms; the outliers were 17, 24, 159 and 298 ms.
  • By caller, in the CPU profile: getLocalEnvironmentEnabled (preload.cjs:318) accounted for 460 ms, and getLocalEnvironmentBootstraps (preload.cjs:312) for about 49 ms.
  • Input latency (EventLatency, KEY_PRESSED, n=1568): p50 9.2 ms, p90 28 ms, p99 64 ms, max 152 ms. The slowest keystrokes were blocked by the 339 ms sync IPC task.
  • desktop.trace.ndjson for the same minutes: 740 desktop:get-local-environment-* handler calls, max 0.41 ms. The handler is fast, and the renderer waits in transport or main-process queueing. One desktop:context-menu invoke in the same window took 2.76 s on the main process.

At this tag apps/desktop/src/preload.ts:106/115 still uses ipcRenderer.sendSync, polled every 3 s from apps/web/src/connection/platform.ts:426. Converting these to async invoke (as #12698 attempted) or pushing topology changes from main instead of polling should remove these stalls.

A separate, smaller observation from a non-stuttering capture: the composer spends about 8 ms of main-thread time per keystroke (keypress/textInput/input dispatch through Tiptap dispatchTransaction → onSelectionUpdate). At 200 Hz that is over the 5 ms frame budget, so most keystrokes miss one frame even without the IPC stalls.


Written by Claude Code (Claude Opus 5.5) via t3 triage.

Synced from GitHub

Mac control data from the nightly performance audits, to distinguish the synchronous-IPC path from proof of Windows typing lag:

  • Captured 29,598 getLocalEnvironmentBootstraps and 15,706 getLocalEnvironmentEnabled calls, via sendSync.
  • Visible-window groups recur at approximately the platform poll interval of 3 seconds, commonly two bootstrap reads plus one enabled read.
  • Main-side duration on this Mac was small: p50 about 0.11 ms, p95 about 0.25 ms, maximum 15.5 ms.
  • Including wrapper spans, these polls accounted for roughly 239k of 269k desktop spans (~89%), with a significant effect on trace rotation/history.

Build: 0.0.46-nightly.20261014.3132 and earlier retained desktop traces, Apple M5/macOS. This confirms redundant sync IPC and trace churn but does not reproduce or explain the severe Windows input stalls reported above. Closed duplicate #19505 points here; this is one consolidated data point, not another duplicate issue. No live Windows validation was performed.