Skip to content

[Bug]: Terminal paste lands twice in Chromium browsers (inverse of the #8457 race) #13346

Description

@r4iju

In the web client (Brave, over the network), pasting into the integrated terminal often sends the text twice. I hit it constantly.

The paste shortcut starts navigator.clipboard.readText() and keeps the native paste event as a fallback (apps/web/src/terminal/ghostty/surface.ts). pasteShortcutToken only handles the native event arriving first. If the read resolves first, the native paste that follows is also sent. This is the "remaining inverse ordering" noted when #8457 was closed.

I have a small fix with a regression test in my fork: the read records the text it delivered, and the matching native paste from the same gesture is dropped. Any keydown clears the record, so a later paste is never swallowed. Reference commit: r4iju@de8ff28

Happy to open a PR if you want it.

Activity

  1. juliusmarminge commented on Sep 24, 2026

    @juliusmarminge
    Member

    Confirmed on main @ 894d33419d. Checked from source only. The shortcut/native paste race in GhosttyTerminalSurface is unchanged. This is the inverse ordering left open when #8457 was closed, not a duplicate of #11955.

    What happens

    The paste shortcut starts navigator.clipboard.readText() and does not cancel the browser's paste:

    https://github.com/pingdotgg/t3code/blob/main/apps/web/src/terminal/ghostty/surface.ts#L1119-L1140

    onPaste always writes non-empty text/plain to the PTY. The token bump only invalidates a read that has not settled yet:

    https://github.com/pingdotgg/t3code/blob/main/apps/web/src/terminal/ghostty/surface.ts#L1231-L1242

    Native-paste-first is covered: onPaste moves pasteShortcutToken, and the read bails on the mismatch. Read-first is not. The read delivers, moves the token, and the paste event that follows still calls onData. That is the hole named when #8457 was closed: the async clipboard read can deliver before a later native paste event. The comment above the read still says the native event always claims the token first. That holds only when the paste event runs inside the keydown default action, before the clipboard task.

    Shortcuts on this path are Cmd+V on macOS, and Ctrl+Shift+V or Shift+Insert elsewhere (isTerminalPasteShortcut, lines 386–396). Plain Ctrl+V on Linux and Windows is still quoted-insert, unless #9201 lands. Desktop uses this same surface, so it is not specific to the hosted web client. #11955 was a second insertion from the Electron Paste as Text accelerator, and that one is already fixed. Context-menu paste goes through pasteFromClipboard, which claims the token before its own read.

    Fix

    de8ff28 is the right shape: the read records the text it sent, and onPaste drops one equal payload. A keydown clears the record so a later gesture is not eaten. The native-first path stays on the token. @r4iju please open that PR. We will not open a competing one.

    Two gaps to close on it:

    1. The record survives the gesture. A shortcut whose browser never fires a paste event (the case the read exists for) leaves shortcutPasteReadText set until the next keydown. Edit → Paste of that same string is an onPaste with no keydown, so it is dropped. The terminal context menu does not hit this; it uses pasteFromClipboard. Also clear the record on the shortcut's keyup. The clipboard spec dispatches that keyboard paste before keyup, so the duplicate from this bug is still dropped.
    2. The new test never flushes the second read. After the second Cmd+V and its native paste, await the clipboard promise and assert onData is still at 2. As written, a second read that also delivers can resolve after the assertion.
  2. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Sep 24, 2026
  3. r4iju commented on Oct 5, 2026

    @r4iju
    Author

    The fix for this is in #13357. It was closed for missing interaction evidence, and has since been updated with before/after recordings in its Verification section (macOS 27, Brave installed web app): a shortcut paste now lands once, and a later same-text Edit → Paste still lands after keyup and after blur. The branch is unchanged and still merges cleanly into main. Could #13357 be reconsidered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions