Terminal sends `\x1b[<0;NaN;NaNm` to the pty when a file link is activated by ctrl+click
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
## Version
- VS Code: 1.117.0 (stable)
- Remote: Dev Containers / remote server (Linux x86_64, kernel 6.8.0)
- Shell: zsh inside tmux 3.5a, `TERM=screen-256color`
- Renderer: default
## Steps to reproduce
1. In the integrated terminal, start tmux with mouse reporting enabled (`set -g mouse on`, the
common default in user configs).
2. Move the terminal into the **editor area** so it occupies an editor tab
(`Terminal: Move Terminal into Editor Area`).
3. Print a path that VS Code detects as a file link, e.g.
`echo $HOME/.tmux.conf`
4. Ctrl+click the link to follow it. The file opens in an editor, replacing the terminal tab.
5. Return to the terminal tab.
## Expected
The link is followed. Nothing is written to the pty, or a well-formed SGR mouse report is.
## Actual
Garbage text appears on the shell prompt line, e.g. `aN;NaNm`. It is not merely painted —
it is real terminal *input* sitting in zsh's line editor buffer, so the next command typed
runs with that prefix attached.
Capturing the raw bytes with `cat -v` in a tmux pane and then ctrl+clicking a link shows
exactly what is sent to the pty:
```
$ cat -v
^[[<0;NaN;NaNm
^[[<0;NaN;NaNm
```
## Assessment by Claude
So VS Code emits an SGR mouse **release** report (final byte `m`, mode 1006) whose column and
row parameters are the string `NaN`. Notably there is no corresponding press report (`M`) —
the press is consumed to activate the link, and only the release is forwarded.
tmux cannot parse the malformed report. Its input parser consumes the CSI through the first
final byte (`\x1b[<0;N` — `N` is 0x4E, a valid CSI final byte), and the remaining bytes
`aN;NaNm` are passed through to the pane as ordinary keystrokes, which is what lands in the
shell's line buffer.
## Analysis by Claude
The coordinates are computed from the mouse event against the terminal's cell metrics. When
the link is activated, the editor opens and replaces the terminal's editor tab, so by the time
the mouseup is processed the terminal element is no longer laid out: its bounding rect and the
render service's CSS cell dimensions are both `0`. The coordinate math then evaluates `0 / 0`,
yielding `NaN`, which is interpolated into the mouse report and written to the pty verbatim.
Two suggested fixes, independent of each other:
1. Validate coordinates before writing a mouse report — drop the event (or clamp) if the
computed column/row is not a finite number. A `NaN` should never reach the pty.
2. Do not forward the mouseup at all when the corresponding mousedown was consumed to
activate a link, since the press/release pair is already asymmetric.
## Notes on scope
- Reproduces only with mouse reporting enabled. Without tmux (or with `set -g mouse off`)
clicks are not forwarded, so nothing is malformed.
- Requires the terminal to be in the editor area, where following a link hides the terminal.
With the terminal in the panel it stays laid out and the coordinates remain valid.
- Impact is beyond cosmetic: arbitrary bytes are injected into the user's shell input buffer.
Contributor guide
Assessment
This issue has not been assessed yet.