BMP→PNG conversion fails silently on WSL2: sharp native module not loadable from bun binary
Summary
Image paste (Ctrl+V) fails on WSL2 with "No image found in clipboard" despite the BMP clipboard detection fix from #25935 being present in v2.1.80. The detection works, but the BMP→PNG conversion fails silently because the sharp native module can't load from the bun-compiled binary.
Environment
- Claude Code v2.1.80 (ELF binary, bun-compiled)
- WSL2 on Windows (WSLg provides Wayland clipboard)
wl-paste -lreturnsimage/bmp
Root Cause
The clipboard paste flow in the compiled binary:
checkImage— runswl-paste -l | grep -E "image/(png|jpeg|jpg|gif|webp|bmp)"→ succeeds (matchesimage/bmp) ✓saveImage— falls through the||chain towl-paste --type image/bmp > "$D"→ succeeds (writes valid BMP file) ✓- JS BMP→PNG conversion — detects
BMmagic bytes, callssharp(D).png().toBuffer()→ throws becausegetNativeModule()returnsnull(native.nodeaddon can't load from bun's virtual FS) ✗ - Outer
try/catchswallows the error and returnsnull→ user sees "No image found in clipboard"
The relevant code path:
// getNativeModule - always returns null in bun binary
function wsD() {
try { _G$ = BAL() } // fails: native addon not loadable
catch { _G$ = null } // silently returns null
return _G$
}
// sharp wrapper - throws when native module unavailable
function zsD(H) {
async function D() {
let M = wsD();
if (!M) throw Error("Native image processor module not available");
...
}
}
// Paste handler - swallows the error
async function TJH() {
try {
...
let D = readFileBytesSync($);
if (D[0] === 66 && D[1] === 77) // BMP detected
D = await sharp(D).png().toBuffer(); // throws here
...
} catch { return null } // "No image found"
}
Verification
Ran the saveImage shell commands manually without any wrapper:
xclip png → exit 1, 0 bytes (no PNG on clipboard)
wl-paste png → exit 1, 0 bytes
xclip bmp → exit 1, 0 bytes
wl-paste bmp → exit 0, 1083750 bytes ✓ (valid BMP with BM magic)
The file is saved correctly. The failure is purely in the JS-side BMP→PNG conversion.
Confirmed sharp native module is not available:
- No
.nodefiles found under~/.local/share/claude/ - Binary is bun-compiled; bun cannot load
.nodenative addons from its virtual FS (related: #32185)
Suggested Fix
Do the BMP→PNG conversion at the shell level in saveImage instead of relying on sharp. For example, append an ImageMagick conversion to the BMP fallback:
# Instead of saving raw BMP and converting in JS:
wl-paste --type image/bmp 2>/dev/null | convert bmp:- png:"${D}" 2>/dev/null
Or use ffmpeg:
wl-paste --type image/bmp 2>/dev/null | ffmpeg -i pipe:0 -f png pipe:1 > "${D}" 2>/dev/null
This removes the dependency on sharp for this specific code path. The sharp-based conversion can remain as a secondary fallback for cases where the file is already saved as BMP.
Current Workaround
A wl-paste wrapper script at ~/.local/bin/wl-paste that intercepts --type image/png requests, fetches BMP from the real wl-paste, and converts via ImageMagick:
#!/bin/bash
REAL_WL_PASTE="/usr/bin/wl-paste"
if [ "$1" = "-l" ] || [ "$1" = "--list-types" ]; then
types=$("$REAL_WL_PASTE" "$@" 2>/dev/null)
echo "$types" | sed 's|image/bmp|image/png|g'
elif [ "$1" = "-t" ] || [ "$1" = "--type" ]; then
if [ "$2" = "image/png" ]; then
types=$("$REAL_WL_PASTE" -l 2>/dev/null)
if echo "$types" | grep -q "image/bmp"; then
"$REAL_WL_PASTE" -t image/bmp 2>/dev/null | convert bmp:- png:-
else
"$REAL_WL_PASTE" -t image/png 2>/dev/null
fi
else
"$REAL_WL_PASTE" "$@"
fi
else
"$REAL_WL_PASTE" "$@"
fi
Requires: sudo apt install imagemagick wl-clipboard
Related Issues
- #25935 — BMP added to grep pattern (fixed detection, but conversion still broken)
- #32185 —
image-processor.nodenot loadable from bun virtual FS - #33538 — sharp module not bundled on Windows/Cursor
- #13738 — Original clipboard paste not working on WSL
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗