[BUG] Image paste (Ctrl+V) does not work in native WSL2 terminal on Windows 11
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When running Claude Code inside a native WSL2 terminal on Windows 11, copying an image from Windows (e.g. Ctrl+C on a file in
File Explorer, or copying an image from a browser) and then pressing Ctrl+V in the Claude Code prompt does not paste the
image. Nothing happens, or only an empty/garbled string is inserted; the image is never attached to the message.
To be explicit: this is reproduced in the native Windows Terminal / wsl.exe shell running a WSL2 distro, not the VS Code
integrated terminal.
Expected: the image is attached to the input as an image, the same way it works in Claude Code on macOS or in the VS Code
integrated terminal.
Actual: the image is not attached. The clipboard image is silently dropped.
Environment:
- OS: Windows 11
- Shell: WSL2 (Ubuntu) running in native Windows Terminal / wsl.exe
- Claude Code: <v2.1.145>
- Node: <v22.22.11>
Notes / likely cause: WSL2's clipboard interop does not expose image/png to Linux clipboard tools by default. xclip / wl-paste
either aren't installed or can't read the Windows clipboard image bytes. To bridge this, the CLI needs a WSL-specific path
that reads the Windows clipboard via powershell.exe (e.g. Get-Clipboard -Format Image or the
System.Windows.Forms.Clipboard.GetImage() API), saves it to a temp PNG, and attaches that. Other CLIs (e.g. Codex) appear to
do this and image paste works there in the same WSL2 environment.
What Should Happen?
Pressing Ctrl+V in the Claude Code prompt inside a native Windows 11 WSL2 terminal should attach the image currently on the
Windows clipboard to the input — same behavior as paste-image on macOS Terminal, iTerm2, or the VS Code integrated terminal.
Specifically, when running in WSL Claude Code should detect WSL (e.g. via WSL_DISTRO_NAME / /proc/version) and, on image
paste, fall back to invoking powershell.exe to read the Windows clipboard image, write it to a temp PNG inside the WSL
filesystem, and attach that file as an image to the message.
Error Messages/Logs
Steps to Reproduce
Repro:
- Windows 11 host, WSL2 distro (e.g. Ubuntu).
- Open Windows Terminal (or wsl.exe directly), launch Claude Code inside the WSL distro.
- In Windows, copy an image to the clipboard (right-click an image file → Copy, or copy an image from a webpage).
- Focus the Claude Code prompt and press Ctrl+V.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
v2.1.145
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
WSL (Windows Subsystem for Linux)
Additional Information
_No response_
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
also facing same issue
Same symptom here on WSL2 + Windows Terminal.
Claude Code 2.1.199, Debian WSL, Windows Terminal 1.24.11321.0.
Alt+V shows “Pasting...” then attaches nothing.
WSL sees the clipboard as image/bmp:
wl-paste --list-types
=> image/bmp
BMP compression is BI_BITFIELDS:
wl-paste --type image/bmp > /tmp/clip.bmp
xxd -l 4 -s 30 /tmp/clip.bmp
=> 03 00 00 00
Manual conversion works:
wl-paste --type image/bmp | convert bmp:- /tmp/clip.png
This looks like #50552: Claude Code receives the WSLg BMP but silently fails converting BI_BITFIELDS BMP to PNG.
Still reproduces on 2.1.238 (native install, WSL2 2.3.26.0 / WSLg 1.0.65, Ubuntu, Windows 10.0.26200). Adding a root cause that I think reframes this issue, plus an A/B measurement and a user-side workaround.
The PowerShell path the OP asks for already exists — it is just unreachable.
Extracted from the shipped 2.1.238 binary, the WSL command set is the
linuxone with two WSL-only suffixes appended (Wt()==="wsl"):WSLg bridges the Windows clipboard image to Wayland only, and only as
image/bmp(X11 exposes no image target at all —xclip -t TARGETS -oreturns justTIMESTAMP TARGETS UTF8_STRING TEXT). So branch 4 succeeds, the||chain short-circuits, and the PowerShell branch — the only one that yields a real PNG — never runs. The subsequent BI_BITFIELDS BMP→PNG conversion then throws, thecatchreturnsnull, and the UI reportsNo image found in clipboard.So this is not "WSL has no path to the Windows clipboard". It is "the working path is behind a branch that succeeds with an unusable format".
Forensic marker that pins the failing step.
saveImage's output file is deleted only on the success path, so its presence localizes the abort, and its first two bytes say why:The file is named
.pngand contains a BMP. It survives every failed paste.A/B on one machine, same clipboard image, only difference is whether
wl-pasteis on PATH:| | branch taken | output | result |
|---|---|---|---|
|
wl-pastepresent | 4 (wl-paste --type image/bmp) | 3 342 402 B, magic42 4d| conversion throws → "No image found" ||
wl-pastehidden | 5 (PowerShell) | 81 204 B, magic89 50, validPNG 1088x768 RGBA| pastes correctly |User-side workaround that actually fixes it today: remove
wl-clipboard(sudo apt remove wl-clipboard). Withwl-pastegone the chain falls through to PowerShell and paste works natively again — no helper scripts. On WSLg,xclipstill covers copy (verified:xclip -selection clipboard→ Windows clipboard round-trip works), so the only loss is Pillow'sImageGrab.grabclipboard(). Side benefit: 56 KB PNG instead of a 3.3 MB uncompressed BMP per paste.Suggested fix: on WSL, try the PowerShell branch before the
image/bmpbranches (or skip the BMP branches entirely whenWt()==="wsl"). That avoids the BI_BITFIELDS decode path rather than trying to make it work, and needs no new dependency. Note thatcheckImagehas the same ordering, but it is harmless there because it only tests for presence.On the duplicate chain: #77102 was auto-closed as a duplicate of #50552, which is itself closed
not_planned/stale, and #36420 was auto-closed against #32185 (a different, VS Code-specificimage-processor.nodebug). The BMP reports have effectively been closed into a dead end, which may be why this keeps getting re-filed.