cd /news/ai-tools/why-ctrl-v-won-t-paste-images-in-cla… · home topics ai-tools article
[ARTICLE · art-15954] src=rajveerbachkaniwala.com pub= topic=ai-tools verified=true sentiment=· neutral

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

Anthropic's Claude Code fails to paste images from the Windows clipboard when used inside Windows Subsystem for Linux (WSL) through Windows Terminal due to three compounding issues: WSLg converts images to an outdated BMP format Claude Code cannot read, WSLg overwrites any PNG workaround placed on the Linux clipboard, and Windows Terminal intercepts the Ctrl+V keystroke before Claude Code receives it. A developer built a fix consisting of a Windows program that converts images to PNG, a Linux script that places the PNG on the Linux clipboard and re-asserts it after WSLg overwrites it, plus a keybinding change to ensure the keystroke reaches Claude Code. The workaround addresses a known bug tracked on GitHub until upstream fixes are released.

read8 min publishedMay 25, 2026

tl;drUse 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.

— runs on Windows and encodes each clipboard image as a real PNG via Windows’ own GDI+. Sidesteps the BMP problem (#1).clip-listener.exe

— runs in WSL, pushes the PNG onto the Linux clipboard withwsl-clip-bridge

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’schat:imagePaste

handler without going through Ctrl+V, which Windows Terminal would eat. Routes around #3.

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:

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 — 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 rm

s, and taking the relevant snippets out of .bashrc

and ~/.claude/keybindings.json

. Nothing else on the system depends on it.

── more in #ai-tools 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/why-ctrl-v-won-t-pas…] indexed:0 read:8min 2026-05-25 ·