BMP→PNG conversion fails silently on WSL2: sharp native module not loadable from bun binary

Resolved 💬 3 comments Opened Mar 20, 2026 by kartik-joshi-01 Closed Mar 23, 2026

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 -l returns image/bmp

Root Cause

The clipboard paste flow in the compiled binary:

  1. checkImage — runs wl-paste -l | grep -E "image/(png|jpeg|jpg|gif|webp|bmp)"succeeds (matches image/bmp) ✓
  2. saveImage — falls through the || chain to wl-paste --type image/bmp > "$D"succeeds (writes valid BMP file) ✓
  3. JS BMP→PNG conversion — detects BM magic bytes, calls sharp(D).png().toBuffer()throws because getNativeModule() returns null (native .node addon can't load from bun's virtual FS) ✗
  4. Outer try/catch swallows the error and returns null → 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 .node files found under ~/.local/share/claude/
  • Binary is bun-compiled; bun cannot load .node native 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.node not loadable from bun virtual FS
  • #33538 — sharp module not bundled on Windows/Cursor
  • #13738 — Original clipboard paste not working on WSL

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗