tui: image paste fails silently on WSL when no clipboard tool is installed (V2) · Issue #49895 · anomalyco/opencode · GitHub
Skip to content

tui: image paste fails silently on WSL when no clipboard tool is installed (V2) #49895

Open

Description

@jaimepa17

Summary

opencode V2 on WSL2: pasting an image (Ctrl+V) does nothing when the Linux
clipboard tools (wl-clipboard/xclip) are not installed. No error, no hint.
opencode should either read the Windows clipboard directly (zero Linux
dependencies) or show a clear install message.

Reproduction

  1. WSL2 without wl-paste/xclip (default state).
  2. Install opencode V2: curl -fsSL https://opencode.ai/v2/install | bash.
  3. On Windows, copy an image (e.g. Win+Shift+S screenshot).
  4. In the TUI (Windows Terminal), press Ctrl+V.
  5. Result: nothing happens. No attachment, no error message.

Windows Terminal (1.24.11911.0) sends an empty bracketed paste for
image-only clipboards (microsoft/terminal #20037), so the TUI reaches
prompt.paste -> clipboard.read(), which returns undefined silently.

Root cause (what to look for)

packages/tui/src/clipboard.ts read() on Linux tries, in order:
wl-paste -t image/png -> xclip -t image/png -o -> clipboardy.
When the first two are missing, the clipboardy fallback fails silently in
standalone binaries (same root cause as #13800 / PR #48611), and
prompt.paste treats undefined as "nothing to paste" with no feedback.

Proposed solutions

  1. WSL: read the Windows clipboard via powershell.exe interop first
    (when os.release() contains "WSL"). Requires no Linux packages; verified
    working on the reporter's machine.
  2. read() should report failure instead of returning undefined, so the TUI
    can show an actionable message (e.g. sudo apt install xclip wl-clipboard).
  3. Accept image/bmp from wl-paste: WSLg syncs the image as image/bmp,
    so requesting only image/png misses it.
  4. Optional: offer the one-line install command (never install silently).

Environment

  • opencode v2.0.8 (V2 standalone binary, curl installer)
  • WSL2, kernel 6.18.33.1-microsoft-standard-WSL2 (Windows 11)
  • Windows Terminal 1.24.11911.0, bash, no plugins

Activity

  1. self-assigned this
    on Sep 25, 2026
  2. venabled commented on Oct 6, 2026

    @venabled

    Still having issues with this in 2.0.24, and fails even when the wsl2 command line clipboard tools are installed. wsl2 via Windows Terminal, ubuntu 24.04 as the guest.

  3. tkoziara commented on Oct 14, 2026

    @tkoziara

    Still reproducible on v2.0.28, with a fairly narrow isolation that may help
    pin it down.

    Environment

    • opencode v2.0.28 (curl installer, standalone binary)
    • WSL2, Ubuntu 24.04.5, kernel 5.15.167.4-microsoft-standard-WSL2
    • Windows Terminal
    • No plugins, no custom provider config affecting the prompt
    • xclip, xsel, wl-clipboard all absent (as in the original report)
    • powershell.exe interop present

    What works / what doesn't

    Action Result
    Ctrl+V with text on the clipboard pastes normally
    Ctrl+V with an image on the clipboard (Win+Shift+S) nothing — no attachment, no error, no log
    Pasting a local file path into the prompt attaches the image correctly

    That last row is the important one: the attachment pipeline itself is healthy.
    Only the clipboard image read is broken.

    Evidence against the causes proposed here

    The description points at read() trying wl-paste → xclip → clipboardy in
    packages/tui/src/clipboard.ts. That doesn't match 2.0.28 — strings on the
    binary finds zero references to wl-paste, wl-copy, xclip, or xsel
    (sanity-checked: the same extraction returns 56 hits for bash, 278 for git,
    1325 for node). The clipboard reader appears to have been reworked into a
    host-provider with a terminal fallback and status-based errors, so the described
    chain may no longer be the path taken.

    I also can't reproduce the image/bmp angle from the third proposed solution.
    With a Win+Shift+S capture on the clipboard, the Windows side reports:

    System.Drawing.Bitmap
    Bitmap
    PNG
    

    PNG is offered, and the reader requests preferredTypes: ["image/png", "text/plain"],
    so a MIME mismatch doesn't explain this here.

    The Windows→WSL bridge is also fine — the same image crosses over intact via
    interop:

    $ powershell.exe -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; ..."
    # saves a valid 1114x378 PNG
    

    The silent path

    The reader is now something like this (from the bundled chunk):

    async read() {
      let e = await r.read({ preferredTypes: ["image/png", "text/plain"], selection: "clipboard" })
      if (e.status !== "read") {
        if (e.status === "failed")        throw e.error
        if (e.status === "timed-out")      throw Error("Clipboard read timed out")
        if (e.status === "limit-exceeded") throw RangeError(...)
        return                    // <-- undefined, no error, no log
      }
      ...
    }

    Any status outside those three hits the bare return and the paste is a
    silent no-op — which is exactly the "no error, no hint" symptom. The fix this
    issue asks for under the second proposed solution (report failure rather than
    returning undefined) doesn't appear to be in 2.0.28.

    For completeness: I tried prompt.paste with "preventDefault": true in
    cli.json to rule out terminal interception. It made no difference for images.
    (The command ID is prompt.paste; input_paste isn't accepted by the
    cli.json schema, in case that's useful to document.)

    Config is a dead end

    I checked the full published cli.json schema — there is no option that affects
    clipboard reading. The only adjacent settings are display-only
    (prompt.paste: "compact" | "full" and image_preview: boolean).

    Workaround in use

    A small script does the job via PowerShell interop, no Linux packages required —
    it pulls Clipboard::GetImage(), writes a PNG, and puts the resulting path on
    the clipboard so it can be pasted normally (attaching via path). Happy to
    contribute it if a WSL-specific helper would be welcome, but the real fix is
    either surfacing the error or reading the Windows clipboard directly on WSL as
    suggested in the first proposed solution.

    Courtesy of Space Bunny Free

  4. simonklee commented on Oct 14, 2026

    @simonklee
    Member

    Thanks - i'll put it on my backlog. I'm on holiday this week so wont be able to look at it until ~7 days

  5. venabled commented on Oct 14, 2026

    @venabled

    After upgrading wsl2 to 3.0.3.0, and installing the x-11/clipboard tools from apt, on ubuntu 24.04 wsl2 guest, it's been working for me

  6. fauzanharsya commented on Oct 15, 2026

    @fauzanharsya

    I had the same issue on OpenCode v2.0.29, running in WSL Ubuntu through both VS Code's integrated terminal and Windows Terminal.

    In my case, XDG_RUNTIME_DIR was set to ~/.local/state and WAYLAND_DISPLAY was wayland-0. The resulting socket path didn't exist, while the WSLg socket was available at /mnt/wslg/runtime-dir/wayland-0.

    Setting the absolute socket path fixed image paste for me:

    export WAYLAND_DISPLAY=/mnt/wslg/runtime-dir/wayland-0

    Run that before launching OpenCode.

    To persist it in Bash, add this guarded version to ~/.bashrc:

    if [ -n "${WSL_DISTRO_NAME:-}" ] &&
       [ "${WAYLAND_DISPLAY:-}" = "wayland-0" ] &&
       [ -S /mnt/wslg/runtime-dir/wayland-0 ]; then
        export WAYLAND_DISPLAY=/mnt/wslg/runtime-dir/wayland-0
    fi

    After saving the change to ~/.bashrc, exit OpenCode and run:

    source ~/.bashrc
    opencode

    Then copy an image in Windows and press Ctrl+V in the OpenCode prompt.

    This fixed it for me, but I haven't determined what originally changed XDG_RUNTIME_DIR. This workaround may help others with the same environment mismatch. For comparison, image paste worked for me in OpenCode v1.19.0 without any manual changes to XDG_RUNTIME_DIR or WAYLAND_DISPLAY.

  7. tkoziara commented on Oct 15, 2026

    @tkoziara

    Fixed by updating WSL 2.4.11.0 → 3.0.3.0 (kernel 5.15.167.4 → 6.18.54.1), which carried WSLg 1.0.65 → 1.0.79. Image paste then worked with no OpenCode change and no config change. Installing xclip/xsel/wl-clipboard alone was not sufficient. Worth noting the reader in 2.0.28 contains no references to those tools, so I suspect WSLg 1.0.65 simply wasn't bridging image clipboard data to the WSL display server — which matches this being a WSL/WSLg issue rather than an OpenCode one. (says Space Bunny)

  8. AlexeyShirshov commented on Oct 20, 2026

    @AlexeyShirshov

    Confirming this on v2.1.0, WSL2 + Windows Terminal.

    Environment: no WSLg runtime dir (/mnt/wslg/runtime-dir is absent), DISPLAY and WAYLAND_DISPLAY are unset, and no wl-clipboard/xclip. Text paste works (the terminal inserts it), path paste attaches the image, but Ctrl+V on an image is a silent no-op.

    One detail that may narrow it down: the clipboard now comes from OpenTUI's native host service, not from wl-paste/xclip/clipboardy. On the Linux build (libopentui.so) there is no WSL bridge at all - strings finds only WSL_INTEROP/WSL_DISTRO_NAME (terminal detection), no powershell/Get-Clipboard. So on WSL the read has no Windows clipboard to talk to unless WSLg happens to bridge Wayland, which is why the WSLg upgrade fixes it for some people but not everyone.

    I'd like to send a small PR for this issue:

    1. When running under WSL and the host read yields nothing, read the Windows clipboard image through powershell.exe ([System.Windows.Forms.Clipboard]::GetImage() -> PNG -> base64), i.e. the interop path V1 used.
    2. If that interop itself fails, surface an error instead of returning undefined, so the paste stops failing silently.

    Keeping it scoped to the clipboard image read; happy to coordinate if you already started on it.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions