Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/web
Steps to reproduce
Intermittent. It happened during one session of drags while a spinner was running. Later attempts didn't reproduce it, including drags while find / was streaming output.
-
Open the right-panel terminal in a thread (macOS desktop app, zsh).
-
Run a command with a progress spinner, for example
curl -fsSL https://vite.plus | bash. -
While it runs, drag the divider between the chat and the terminal to make the terminal narrower, then let go.
-
After the command finishes, wait a few seconds without touching anything and run:
stty size; printf '%*s|\n' "$(( $(tput cols) - 1 ))" '' | tr ' ' '='
This prints the size the PTY reports, then a line exactly that many columns wide.
Expected behavior
stty size matches the width the terminal draws, so the ====| line ends exactly at the right edge. Spinners redraw in place.
Actual behavior
- While the spinner ran, each redraw landed further along the row. The output became a staircase of repeated
Installing dependencies... 1slines, which stayed in the scrollback (screenshot 1). - Afterwards,
stty sizeprinted51 110while the panel showed about 86 columns. The full-width line wrapped by about 24 characters (screenshot 2). The PTY kept the old width even though nothing had been resized for a while. - Dragging the divider again fixed it:
stty sizethen printed51 84, matching the panel. - The same command in macOS Terminal.app, resized the same way while it ran, renders cleanly.
From reading the code (not confirmed): GhosttyTerminalSurface.fit() in apps/web/src/terminal/ghostty/surface.ts stores the new size and sends it once through notifyResize (150 ms debounce, or on pointer release). It only sends again when the measured size changes. If that one message is lost on the way, nothing retries it. Places where it could be lost:
resizeTerminalinThreadTerminalDrawer.tsxreturns early whenwritableSessionGeneration(...)is null.resizeLockedinapps/server/src/terminal/Manager.tsignores a resize from an unregistered viewer while another viewer has a size.- The RPC fails.
Related but different: #25419, where the PTY does get the new size and the shell's redraw disagrees with Ghostty's reflow. Here the PTY never gets the new size.
Impact
Minor bug or occasional failure
Version or commit
T3 Code (Beta) 0.1.7
Environment
macOS 27.2, desktop app, local environment, zsh. The thread was only open in the desktop window.
Logs or stack traces
Screenshots, recordings, or supporting files
Screenshot 2026-11-04 at 22.24.02.png
Screenshot 2026-11-04 at 22.28.34.png
Workaround
Drag the divider again. Any new width sends a fresh size to the PTY.
Activity
juliusmarminge commentedon Nov 4, 2026
Tried this on current main (9e85538); nothing in this resize path has changed since v0.1.7. It did not reproduce, so we need a bit more to narrow it down.
What I ran, web client against a dev server, right-panel terminal, bash:
stty sizecheck. Result:41 44, the====|line ended at the edge, and the spinner redrew in place.41 68, matching the panel.41 83, matching the panel.The surface does resend its size after a reconnect, so a single dropped request does not leave the PTY stale on its own. Your
51 110while the panel showed about 86 columns means the server kept a size that a later resize did not replace. Three things would help us tell which path that was:~/.t3/userdata/logs, especially any lines mentioningterminal.resizeorTerminalResizeError.sands21 commentedon Nov 4, 2026
Thanks for checking!
renderer-history.ndjson), which samples every 30 s, has a five-minute gap from 22:19:26 to 22:24:26 IST, between the spinner screenshot (about 22:16) and thestty sizecheck (22:28). There's another from 22:06:26 to 22:11:26. That looks like the window was throttled in the background or the Mac was idle, which might relate to [Bug]: Hidden desktop window drops and reconnects every environment on a one-minute grid (15 s ping timeout vs background throttling) #21235.server.trace.ndjsonstarts at 22:37:26, because afind /I ran in the terminal at about 22:37 produced about 14,000terminal.drainProcessEvents/terminal.queuePersistspans in five seconds, which filled all ten rotated files. If it happens again, I'll grab the log right away.juliusmarminge commentedon Nov 4, 2026
Thanks for the details. Ruling out other clients narrows it a lot.
Tried again on current main (95e53a5), with the web client against a dev server, the right-panel terminal, and bash. The probe was your
stty size/====|check.41 57, which matches the 459 px panel. The spinner redrew in place.41 44, which matches 359 px.seq 1 4000000streamed while a spinner ran and the divider was dragged wider, then narrower (→ 489 px). Result:41 61, which matches.In each case the PTY ended at the panel's width. The client resends its size whenever it reattaches, so a resize lost to a reconnect recovers by itself. What we haven't been able to exercise is a resize request that fails while the connection stays up. We also can't reach the macOS desktop app's background throttling from here.
If it happens again, these would settle it:
~/.t3/userdata/logs/server.trace.ndjsonanddesktop.trace.ndjson, and do it before running anything with heavy output. We need thews.rpc.terminal.resize/terminal.resizespans from the drag onward: whether one arrived after you let go, and whether any has aFailureexit.Muzammil-Bit commentedon Nov 6, 2026
Note
🤖 Claude Opus 5.5 responding on behalf of Muzammil-Bit
Not reproducible here either, but one path still fits every symptom: a resize request that fails while the connection stays up is never retried.
Reproduction attempt (macOS 27.2, current main, web client against a dev server, right-panel terminal): a spinner redrawing every 100 ms, with the divider dragged narrower mid-run. Result:
41 67before,41 44after, and the====|line ended at the edge. The spinner redrew in place.Ruled out by reading the code:
latestresize lane: that would also block later resizes, but dragging again fixed it.backgroundThrottling: false. The five-minute gaps inrenderer-history.ndjsoncome from main-process sampling, so they point to system sleep or the whole app being suspended, not the renderer.The remaining path (code reading, not observed):
process.resizeinsideEffect.try(Manager.ts#L259). node-pty throws whenioctl(TIOCSWINSZ)fails, so the RPC fails withTerminalResizeErrorandsession.colsstays at the old width.reportFailure: false(ThreadTerminalDrawer.tsx#L585), so the failure is silent.That gives a PTY stuck at the old width with no time limit, fixed by the next drag to a new width, which is what was reported.
If it happens again, the useful evidence is a
terminal.resizespan with aFailureexit, or aTerminalResizeError, inserver.trace.ndjsonfrom the drag onward. If one shows up, the fix is small: resend the size once after a failed resize.