LmCast :: Stay tuned in

Why Ctrl+V won't paste images in Claude Code on WSL, with a fix

Recorded: May 28, 2026, 3 a.m.

Original Summarized

Why Ctrl+V won’t paste images in Claude Code on WSL, with a fix | @rajveerbach’s blog

@rajveerbach's blog

Blog
Categories

Why Ctrl+V won't paste images in Claude Code on WSL, with a fix

Rajveer Bachkaniwala
May 24, 2026 · 8 min read

Links:
Code

tl;dr Use Claude Code in WSL inside Windows Terminal? Copying an image in Windows and pressing Ctrl+V in Claude Code doesn't work. Three things break: (1) WSL only hands Windows images to the Linux side in an old BMP format Claude Code can't read; (2) WSL also keeps quietly overwriting your fixes a moment later; (3) Windows Terminal grabs Ctrl+V before Claude Code can see it. The fix is a small Windows program that converts the image to PNG, a Linux script that puts it on the Linux clipboard (and re-asserts once after WSL overwrites it), and one extra keybinding for Claude Code so the keystroke actually reaches the program.

Copy an image in Windows. Open Claude Code inside a WSL terminal launched from Windows Terminal. Press Ctrl+V. Nothing happens.
Three small things between the Windows clipboard and Claude Code’s chat input are broken. Each one is harmless on its own. Together they make image paste fail completely. Here’s what they are and the workaround I built until the upstream fixes catch up.
What’s actually broken
1. The Windows-to-Linux clipboard sync only knows about an ancient image format
WSL has a built-in piece called WSLg (the “g” is for graphics). Its job is to make Windows and the Linux side share things — including the clipboard, so copy-paste works across the boundary. For text, it works fine. For images, it does two things badly.
First, it only syncs images in one direction: from Windows to Linux. Anything copied from a Linux app doesn’t flow back to Windows as an image.
Second, when WSLg sends a Windows image over to Linux, it converts it into a single, dated format — a specific old BMP variant that uses an obscure colour encoding (“BI_BITFIELDS”). Most software’s BMP readers can’t handle it. Claude Code’s reader is one of those. It tries to read what arrives, gets nothing useful, and gives up — silently. No error, no toast, no visible failure. The image just doesn’t attach.
(This is a known bug: claude-code#50552.)
2. The same Windows-to-Linux sync silently overwrites your workarounds
You might think: fine, I’ll bypass WSLg for images. Read the Windows clipboard myself, convert the image to PNG, push the PNG straight onto the Linux clipboard. Claude Code will then find a PNG when it looks for an image, and the paste will work.
There’s even a standard Linux command for putting things on the clipboard: wl-copy. So you do exactly that — Windows image → PNG → wl-copy --type image/png.
It works. For a moment. Then it stops working again. Here’s what WSL does to you:

You put a PNG on the Linux clipboard.
WSLg notices the Linux clipboard changed, and dutifully syncs it back to Windows. The Windows clipboard now reflects “PNG.”
The Windows clipboard just changed. That fires WSLg’s other half — the half that pushes Windows changes over to Linux. As we know from problem #1, that half only knows how to push BMP.
So your good PNG on the Linux side gets overwritten with the broken BMP, shortly after you put it there.

The cruellest part: the program you wrote to watch the Windows clipboard never sees step 4 happen. WSLg writes to the Linux clipboard directly — it doesn’t go through the Windows clipboard to do it. So from your watcher’s point of view, the Linux clipboard just silently mutates, with nothing for you to react to.
3. Windows Terminal eats Ctrl+V before Claude Code sees it
Suppose you fix everything above and a real PNG sits reliably on the Linux clipboard. Press Ctrl+V in Claude Code. Still nothing happens.
The reason: Windows Terminal — the program you’re typing into — has its own meaning for Ctrl+V. It’s the standard “paste text from the Windows clipboard” shortcut. So when you press Ctrl+V inside Windows Terminal:

Windows Terminal sees the keystroke first.
It pastes (or tries to paste) the Windows clipboard as text into the terminal input.
The keystroke never makes it down to the Linux side.
Claude Code’s image-paste code (internally named chat:imagePaste) never runs.

The terminal is one layer above Claude Code. It eats the input before the program below can react.
The fix
Three small components, one per failure, laid out in the diagram below.

clip-listener.exe — runs on Windows and encodes each clipboard image as a real PNG via Windows’ own GDI+. Sidesteps the BMP problem (#1).
wsl-clip-bridge — runs in WSL, pushes the PNG onto the Linux clipboard with wl-copy, and re-asserts once half a second later if WSLg has overwritten our PNG with the broken BMP. Handles the silent clobber (#2).
Alt+V keybinding in ~/.claude/keybindings.json — triggers Claude Code’s chat:imagePaste handler without going through Ctrl+V, which Windows Terminal would eat. Routes around #3.

What changes when the bridge is installed. Without it (top), images flow straight to Claude Code as broken BMP and the paste fails. With it (bottom), a Windows listener encodes a real PNG and a Linux script puts it on the Linux clipboard, re-asserting once after WSLg's overwrite. The user presses Alt+V instead of Ctrl+V to bypass Windows Terminal.
End to end: snip an image in Windows, press Alt+V in Claude Code, image attaches.
The full source — the Go listener, the bash bridge, the install script, and a more detailed walkthrough — lives at github.com/rajveerb/wsl-clip-bridge.
Try it yourself
Prerequisites: WSL2 with WSLg (Windows 11, or a recent Windows 10 + WSL update), Go 1.20+ on the Linux side for cross-compiling the Windows binary.
git clone https://github.com/rajveerb/wsl-clip-bridge.git
cd wsl-clip-bridge
sudo apt install wl-clipboard
./install.sh --with-autostart --with-keybinding

That last command does four things: cross-compiles the Windows-side listener (GOOS=windows GOARCH=amd64), drops the binaries into ~/.local/share/wsl-clip-bridge/ and ~/.local/bin/, appends a snippet to ~/.bashrc that starts the bridge on every new WSL shell, and writes ~/.claude/keybindings.json with alt+v → chat:imagePaste.
Open a fresh WSL terminal. The bridge starts in the background. Verify:
# copy any image in Windows (Win+Shift+S)
wl-paste -l # should print image/png

Then in Claude Code, press Alt+V. The image attaches.
The repo README walks through each step in more detail (running without the install script, stopping or uninstalling the bridge, debugging via the log).
Whose problem is it?
Four things contribute to the failure. The first problem above (“an ancient image format”) is really two separate issues, so the table splits them apart:

#
Failure
Whose problem

1
WSLg only sends Windows images to Linux as image/bmp
Microsoft (WSLg)

2
Claude Code can’t read the BMP it actually receives
Claude Code — one-PR fix

3
WSLg overwrites the Linux clipboard from Windows, silently
Microsoft (WSLg); only matters because of #1 and #2

4
Windows Terminal grabs Ctrl+V before WSL programs see it
Microsoft (Windows Terminal); Claude Code could route around it

#1 is hardcoded in WSLg’s clipboard bridge (rdpclip.c in Microsoft’s Weston fork): exactly five Windows→Linux format mappings, and the only image one is CF_DIB → image/bmp. The strings image/png and image/jpeg don’t appear in the source. The upstream issue microsoft/wslg#833 has been open since September 2022.
#2 is broader than the post above implies, and more fixable than I first thought. Claude Code bundles sharp as its image library, in its WebAssembly build. That build’s bundled libvips has no BMP loader — not just no BI_BITFIELDS variant, no BMP support of any kind. Claude Code does detect BMP on the clipboard and try to convert it via sharp(bmpBuffer).png().toBuffer(), but the call dies with “Input buffer contains unsupported image format.” Despite the user-facing implication that BMP is supported, sharp’s WASM build can’t read any BMP. The actual upstream fixes are: ship sharp’s native libvips build (which has BMP support); ship a small BMP→PNG converter that doesn’t go through sharp at all; or shell out to ImageMagick or GDI+ on detection failure. Any of these obsoletes this entire bridge.
#3 isn’t hypothetical. The bridge’s log on this machine shows it directly, with timestamped lines like re-asserted clip-1.png (was: image/bmp,) after every Snipping Tool capture. Interestingly, synthetic Clipboard::SetImage calls from PowerShell never triggered it; only the Snipping Tool path did, which suggests WSLg keys off something specific in how Snipping Tool finalises its writes. A single re-assertion at +0.5 s catches it reliably; the three additional retries I tried earlier never fired.
#4 is hardcoded in a place that surprised me. Windows Terminal’s Ctrl+V handler isn’t in defaults.json (that file only binds Ctrl+Shift+V). It’s in ConHost’s windowio.cpp, where the inputKeyInfo check on 'V' with IsInVirtualTerminalInputMode and ShouldTakeOverKeyboardShortcuts swallows the keystroke before the inner program ever sees it. Tracked at microsoft/terminal#5790, open and on “Backlog” since 2020.
The kicker on #4 — Claude Code already defaults chat:imagePaste to Alt+V on native Windows. It just doesn’t apply that default in WSL, because WSL reports as Linux and the Windows-specific code never runs. The cleanest upstream fix isn’t even new functionality: detect “running in WSL inside Windows Terminal” at startup and apply the existing Windows Alt+V default there too. No keybinding file required from the user.
When this stops being needed

WSL starts sending PNG to Linux → the Windows listener is no longer needed.
Claude Code learns to read the BMP variant → the Windows listener is no longer needed.
Windows Terminal stops grabbing Ctrl+V → the custom keybinding is no longer needed.

When all three happen, removing the workaround is one pkill, a couple of rms, and taking the relevant snippets out of .bashrc and ~/.claude/keybindings.json. Nothing else on the system depends on it.

More posts

19 May, 2026
Stream2LLM: Overlap Context Streaming and Prefill for Reduced Time-to-First-Token

© 2026 @rajveerbach's blog
·
X
·
GitHub
·
RSS

The failure of the Ctrl+V command to paste images from the Windows clipboard into Claude Code when operating within a WSL environment launched via Windows Terminal stems from a confluence of three distinct, yet interacting, technical failures. The author, Rajveer Bachkaniwala, details that the issue is not a single bug but the result of several separate problems that compound each other, leading to a complete failure of the image transfer mechanism.

The primary technical breakdown involves the synchronization of images between the Windows environment and the Linux subsystem. WSLg, the component responsible for sharing graphics and clipboard functionality, handles image synchronization imperfectly. It only manages image transfer in one direction, from Windows to Linux, and it converts these images into an outdated, specific variant of the BMP format utilizing an obscure color encoding, which Claude Code’s image reader cannot process. This results in the image failing to attach silently without any error message. Furthermore, this process introduces a secondary conflict where the synchronization silently overwrites any user-implemented workarounds designed to handle the image transfer. This occurs because the system logic responsible for updating the Linux clipboard operates outside the visibility of the custom software monitoring the Windows clipboard, causing the Linux clipboard contents to mutate unexpectedly.

A third layer of failure is caused by the interaction with the host environment, specifically Windows Terminal. When the user presses Ctrl+V inside the terminal, Windows Terminal intercepts the keystroke first, treating it as a request to paste text from the Windows clipboard, thereby preventing the signal from reaching the underlying Linux programs like Claude Code. This interception layer effectively consumes the input before the necessary application logic can execute.

To resolve this complex interplay, the author proposes a three-part solution designed to bypass each failure point sequentially. The proposed fix involves a small Windows program to convert clipboard images into the universally readable PNG format, a Linux script to manage placing the image onto the Linux clipboard and to re-assert the content after potential overwrites from WSLg, and a modification to Claude Code’s keybindings to use an alternative shortcut, Alt+V, which avoids the interception by Windows Terminal.

The proposed solution involves three specific components: clip-listener.exe to handle the format conversion to PNG, wsl-clip-bridge to manage the synchronization and overwrite protection on the Linux side, and a keybinding change in Claude Code to route the paste command around the Windows Terminal intercept. The integration of these components ensures that an image copied in Windows is correctly transformed, securely transferred across the WSL boundary, protected from overwriting, and finally delivered to Claude Code, achieving the desired end-to-end result.

The analysis further attributes responsibility for these failures to specific components: Microsoft for the legacy image format handling in WSLg, Claude Code for its inability to process the resulting BMP variants, Microsoft for the silent overwriting behavior of WSLg, and Windows Terminal for intercepting the standard Ctrl+V input. The post suggests that the eventual upstream solutions lie in updates to these components, such as providing native BMP support, implementing proper conversion formats, and fixing the input handling within the terminal environment. The final state, where the workaround is no longer needed, is achieved when all three root causes are resolved simultaneously.