Bracketed paste mode bug, affects applications like tmux #23671

Closed
opened 2026-01-31 08:48:47 +00:00 by claunia · 3 comments
Owner

Originally created by @bugreporter23 on GitHub (Oct 7, 2025).

Windows Terminal version

1.22.12111.0

Windows build number

10.0.19045.0

Other Software

ubuntu 22.04 LTS vm with the packaged tmux
ssh from powershell, into vm (the vm is NOT wsl; it is VMWare Workstation, but idt it should matter. Pretty sure this is reproducible over any ssh into a linux enviornment. Probably not even over ssh, but that's the limit of my debugging. An even more minimal test would require setting up some kind of keylogger-only application in powershell, disabling any and all "niceties")

Steps to reproduce

Minimal tmux.conf reproduction

set -g assume-paste-time 0

Issue:

Paste the string "a" * 85 (85 a's).

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

(this probably works for other lengths, but this is the most consistent string. It appears to be based on length).

With decently high probability (try this up to ~20 times; it should happen within 5), you will enter a mode in tmux where you cannot use any hotkeys, including prefix. This is because tmux things you are still "pasting" even when you are not. Thus, (prefix) commands will not work. Try prefix + c to create a new window, for example.

Expected Behavior

See below

Actual Behavior

This is a bracketed paste issue. If you strace the server process with

sudo strace -s 200 -e trace=readv,writev -p {tmux server process} 2>&1 | tee temp

you can clearly see malformed bracketed pastes, such as:

readv(26, [{iov_base="\33[200~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\33[201", iov_len=96}], 1) = 96
readv(65, [{iov_base="readv(65, [{iov_base=\"readv(65, [{iov_base=\\\"readv(65, [{iov_base=\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, ["..., iov_len=464}], 1) = 464
readv(65, [{iov_base="readv(65, [{iov_base=\"readv(65, [{iov_base=\\\"readv(65, [{iov_base=\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, ["..., iov_len=316}], 1) = 316
writev(56, [{iov_base="\33[200~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", iov_len=91}], 1) = 91

Some of these calls are not being terminated properly.

Interestingly enough, I was unable to reproduce this by say, arbitrarily increasing the length copy pasted. A length 86 string seems to trigger the same behavior, but a length 90 string doesn't seem to, and length >200 strings dont either. Shrinking to even just length 84 makes the issue unreproducible.

There appears to be no issue with something like neovim, even if this does occur. I'm not sure why, and I haven't verified with neovim internals if they have the same messed up state machine. I suspect that neovim is somehow more robust to this kind of pasting, given that neovim understands itself to be a text editor, while a tmux client only understands you are dealing with an arbitrary tty, so it needs to be more conservative with interpretations (and thus allows you to get stuck in "bad states".)

Also, another piece of evidence that this is window's terminal's issue:

  • I launched wezterm, which allocates its own window, and I run the same ssh test: No issue.
  • I run the vm with "sway" and I copy paste from the default terminal emulator (foot). No issue.

When looking at strace logs, bracketed pastes are not malformed. (Foot even splits bracketed paste into 2 separates messages, 1 open esc code, then rest of string + closed. Still, that plays well with tmux).


This post is a bit schizo, yes. I'm not sure how to debug windows terminal, but hopefully this is reproducible?

Originally created by @bugreporter23 on GitHub (Oct 7, 2025). ### Windows Terminal version 1.22.12111.0 ### Windows build number 10.0.19045.0 ### Other Software ubuntu 22.04 LTS vm with the packaged tmux ssh from powershell, into vm (the vm is NOT wsl; it is VMWare Workstation, but idt it should matter. Pretty sure this is reproducible over any ssh into a linux enviornment. Probably not even over ssh, but that's the limit of my debugging. An even more minimal test would require setting up some kind of keylogger-only application in powershell, disabling any and all "niceties") ### Steps to reproduce Minimal tmux.conf reproduction ``` set -g assume-paste-time 0 ``` Issue: Paste the string "a" * 85 (85 a's). aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (this probably works for other lengths, but this is the most consistent string. It appears to be based on length). With decently high probability (try this up to ~20 times; it should happen within 5), you will enter a mode in tmux where you cannot use any hotkeys, including prefix. This is because tmux things you are still "pasting" even when you are not. Thus, (prefix) commands will not work. Try prefix + c to create a new window, for example. ### Expected Behavior See below ### Actual Behavior This is a bracketed paste issue. If you strace the server process with ``` sudo strace -s 200 -e trace=readv,writev -p {tmux server process} 2>&1 | tee temp ``` you can clearly see malformed bracketed pastes, such as: ``` readv(26, [{iov_base="\33[200~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\33[201", iov_len=96}], 1) = 96 readv(65, [{iov_base="readv(65, [{iov_base=\"readv(65, [{iov_base=\\\"readv(65, [{iov_base=\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, ["..., iov_len=464}], 1) = 464 readv(65, [{iov_base="readv(65, [{iov_base=\"readv(65, [{iov_base=\\\"readv(65, [{iov_base=\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, [{iov_base=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"readv(65, ["..., iov_len=316}], 1) = 316 writev(56, [{iov_base="\33[200~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", iov_len=91}], 1) = 91 ``` Some of these calls are not being terminated properly. Interestingly enough, I was unable to reproduce this by say, arbitrarily increasing the length copy pasted. A length 86 string seems to trigger the same behavior, but a length 90 string doesn't seem to, and length >200 strings dont either. Shrinking to even just length 84 makes the issue unreproducible. There appears to be no issue with something like neovim, even if this *does* occur. I'm not sure why, and I haven't verified with neovim internals if they have the same messed up state machine. I *suspect* that neovim is somehow more robust to this kind of pasting, given that neovim understands itself to be a text editor, while a tmux client only understands you are dealing with an arbitrary tty, so it needs to be more conservative with interpretations (and thus allows you to get stuck in "bad states".) Also, another piece of evidence that this is window's terminal's issue: - I launched wezterm, which allocates its own window, and I run the same ssh test: No issue. - I run the vm with "sway" and I copy paste from the default terminal emulator (foot). No issue. When looking at strace logs, bracketed pastes are not malformed. (Foot even splits bracketed paste into 2 separates messages, 1 open esc code, then rest of string + closed. Still, that plays well with tmux). --- This post is a bit schizo, yes. I'm not sure how to debug windows terminal, but hopefully this is reproducible?
claunia added the Needs-TriageIssue-BugNeeds-Attention labels 2026-01-31 08:48:47 +00:00
Author
Owner

@DHowett commented on GitHub (Oct 7, 2025):

Thanks for the comprehensive report!

The annoying thing that I suspect you (and a lot of other folks, honestly) are running into is documented in tmux issue tmux/tmux#3844.

They lowered the default value for escape-time to 10 milliseconds back in 2024. That value controls how long they will wait between a trailing \e and the rest of a control sequence introducer before bailing out and deciding that it was a lone Esc.

Assuming a network with zero added latency, this will work perfectly for all packets fragmented between the escape character and the control sequence only within 1,862 US miles (2,998 km). Add any line latency at all (like, my machine takes 1-4 ms to make a single hop over wifi to my gateway) and that distance handily cuts in half. Let's assume the midpoint there of 2.5ms, which eats up 465 miles (749 km).

If I happen to send a bracketed paste sequence whose terminator is fragmented between \e and [201~, under ideal conditions with no extra hops I will not see this bug assuming my server is only 1,400 miles away from me.

TL;DR: if you raise tmux's escape-time setting to something more reasonable like 50 or 100, does the problem resolve itself? vim uses a higher default escape time.


I could have sworn that they added a fix where they'd wait longer during bracketed paste. I can't verify that in their commit history or code, however. They definitely extended the time they'll wait when there's an active query (in cfb906a0ce)

@DHowett commented on GitHub (Oct 7, 2025): Thanks for the comprehensive report! The annoying thing that I suspect you (and a lot of other folks, honestly) are running into is documented in tmux issue tmux/tmux#3844. They lowered the default value for `escape-time` to 10 milliseconds back in 2024. That value controls how long they will wait between a trailing `\e` and the rest of a control sequence introducer before bailing out and deciding that it was a lone <kbd>Esc</kbd>. Assuming a network with zero added latency, this will work _perfectly_ for all packets fragmented between the escape character and the control sequence only within 1,862 US miles (2,998 km). Add any line latency at all (like, my machine takes 1-4 ms to make a single hop over wifi to my gateway) and that distance handily cuts in half. Let's assume the midpoint there of 2.5ms, which eats up 465 miles (749 km). If I happen to send a bracketed paste sequence whose terminator is fragmented between `\e` and `[201~`, under ideal conditions with no _extra_ hops I will not see this bug assuming my server is only 1,400 miles away from me. TL;DR: if you raise tmux's `escape-time` setting to something more reasonable like 50 or 100, does the problem resolve itself? vim uses a higher default escape time. --- I could have sworn that they added a fix where they'd wait longer during bracketed paste. I can't verify that in their commit history or code, however. They definitely extended the time they'll wait when there's an active query (in https://github.com/tmux/tmux/commit/cfb906a0ceb18846ac52561c5def88d155c5e54b)
Author
Owner

@bugreporter23 commented on GitHub (Oct 7, 2025):

Thanks! Tentatively closing this issue. 50 feels snappy enough to me. I actually had this setting on 0 before in my old tmux conf, and I guess the default became 10 so I didn't notice in testing (In testing, I realized I tested in a ubuntu 25.04 fresh vm, not the 22.04 one, which checks out with the timeline).

I'm still confused as to why wezterm ssh'd in, and foot (in the vm) seemed to work fine, but I'm assuming you could theoretically trigger this bug on any emulator by finding the right coincedental constants.

Really weird terminal bugs... you learn something new every day.

@bugreporter23 commented on GitHub (Oct 7, 2025): Thanks! Tentatively closing this issue. 50 feels snappy enough to me. I actually had this setting on 0 before in my old tmux conf, and I guess the default became 10 so I didn't notice in testing (In testing, I realized I tested in a ubuntu 25.04 fresh vm, not the 22.04 one, which checks out with the timeline). I'm still confused as to why wezterm ssh'd in, and foot (in the vm) seemed to work fine, but I'm assuming you could theoretically trigger this bug on any emulator by finding the right coincedental constants. Really weird terminal bugs... you learn something new every day.
Author
Owner

@DHowett commented on GitHub (Oct 7, 2025):

terminal bugs... you learn something new every day.

amen to that.

I filed a discussion topic over on tmux about this as well. Thanks for the motivation!

@DHowett commented on GitHub (Oct 7, 2025): > terminal bugs... you learn something new every day. amen to that. I filed a discussion topic over on tmux about this as well. Thanks for the motivation!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#23671