Skip to content

fix: drain OSC response when cursor position reply arrives first - #210

Open
IdLnFb wants to merge 1 commit into
muesli:masterfrom
IdLnFb:fix/drain-osc-response-on-cursor-race
Open

fix: drain OSC response when cursor position reply arrives first#210
IdLnFb wants to merge 1 commit into
muesli:masterfrom
IdLnFb:fix/drain-osc-response-on-cursor-race

Conversation

@IdLnFb

@IdLnFb IdLnFb commented Jun 23, 2026

Copy link
Copy Markdown

Problem

In some terminals (iTerm2, Terminal.app on macOS) the cursor position response to CSI 6n arrives before the OSC 11 background-color response. termStatusReport detected a non-OSC reply and returned early, restoring TTY echo (via the deferred raw-mode teardown) before the OSC response had arrived. That response then arrived with echo ON and was:

  1. Echoed directly to the terminal display as garbled output (^[]11;rgb:0000/1313/1919^[\)
  2. Left in the shell's input buffer, appearing as a phantom command after the process exited

Any interactive prompt rendered after the process exits picks up those buffered bytes — producing corrupted default values or unexpected input.

Fix

When the first response is not an OSC reply, poll for up to 100 ms for a pending OSC response and drain it (including the trailing \ of the ESC\ string terminator) before returning ErrStatusReport.

The 100 ms window is generous for a local Unix PTY without adding noticeable latency on terminals that don't support OSC 11 at all — they send nothing, so the select returns immediately.

Reproducer

Any program that calls HasDarkBackground() during package init triggers this reliably in iTerm2 and Terminal.app. charmbracelet/bubbletea v1 does exactly this in tea_init.go.

In some terminals (iTerm2, Terminal.app on macOS) the cursor position
response to CSI 6n arrives before the OSC 11 background-color response.
termStatusReport detected a non-OSC reply and returned early, but
re-enabled TTY echo (via the deferred raw-mode restore) before the OSC
response had arrived. The OSC response then arrived with echo ON and was:

  1. echoed directly to the terminal display as garbled output, and
  2. left in the shell's input buffer, appearing as a phantom shell command
     after the process exited.

Fix: when the first response is not an OSC reply, poll for up to 100 ms
for a pending OSC response and drain it (including the trailing backslash
of the ESC-backslash string terminator) before returning ErrStatusReport.
The 100 ms window is generous enough for the response to arrive over a
local Unix PTY without adding noticeable latency on terminals that truly
don't support OSC 11.

Reproducer: any program that calls HasDarkBackground() during package
init (e.g. charmbracelet/bubbletea v1 does this in tea_init.go) while
running in iTerm2 or Terminal.app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant