[BUG] Ctrl+V image paste fails for images >2000px since v2.1.98 — bundled sharp resize error silently swallowed

Resolved 💬 4 comments Opened Apr 12, 2026 by RD-Mason Closed May 23, 2026

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?

Summary

Since v2.1.98, pasting clipboard images with dimensions exceeding 2000px via Ctrl+V silently fails with "No image found in clipboard." Images ≤ 2000px paste normally. This is a regression — v2.1.97 handles all image sizes correctly.

Environment

  • Claude Code: 2.1.98+ (tested on 2.1.104, confirmed working on 2.1.97)
  • macOS: 15.x (Darwin 25.3.0), Apple Silicon
  • Terminal: iTerm2 3.4.15
  • Node.js: v20.20.1

Root Cause Analysis

What changed in v2.1.98

The clipboard image processing pipeline was changed. In v2.1.97, the clipboard handler calls:

// v2.1.97 — 3 arguments, no external limits parameter
let A = await eo(Y, Y.length, "png");

In v2.1.98+, it was changed to:

// v2.1.98+ — 4 arguments, passes {maxWidth:2000, maxHeight:2000} limits
let O = await Sa(A, A.length, "png", q);

Why it fails

The sa() function (minified name varies by version) processes images through this flow:

  1. Calls sharp(buffer).metadata() to get dimensions — works fine
  2. If dimensions ≤ 2000x2000 → returns image as-is — works fine
  3. If dimensions > 2000x2000 → calls sharp(buffer).resize(...).toBuffer()FAILS
  4. Error caught by catch { return null } → caller shows "No image found"

The bundled sharp JS wrapper in cli.js cannot successfully perform the resize().toBuffer() operation. The native module (@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node v0.34.5) loads correctly, and a standalone sharp installation can resize the same image without issues. The failure is specific to the bundled sharp code within cli.js.

Verification

| Test | Result |
|------|--------|
| osascript -e 'the clipboard as «class PNGf»' | ✅ Works (exit code 0) |
| osascript save to file | ✅ Works (writes valid PNG) |
| Node.js spawn with maxBuffer: 100MB | ✅ Works |
| Standalone sharp(buf).resize(2000, 904).toBuffer() | ✅ Works |
| Bundled sharp resize in cli.js | ❌ Fails silently |
| Paste image ≤ 2000px (no resize needed) | ✅ Works |
| Paste image > 2000px (resize triggered) | ❌ Fails |

Confirmed version bisect

| Version | maxWidth/maxHeight limits | Clipboard calls sa() with limits | Status |
|---------|--------------------------|----------------------------------|--------|
| 2.1.97 (2026-04-08) | Global vars TQ=2000, VQ=2000 | eo(buf, len, "png") — 3 args | ✅ Works |
| 2.1.98 (2026-04-09) | maxWidth:2000, maxHeight:2000 | Sa(buf, len, "png", limits) — 4 args | ❌ Broken |
| 2.1.100 | Same | Ra(buf, len, "png", limits) | ❌ Broken |
| 2.1.104 | Same | sa(buf, len, "png", limits) | ❌ Broken |

What Should Happen?

Images larger than 2000px should either:

  1. Be resized successfully using sharp before sending, OR
  2. Fall back to sending the original image if resize fails (the base64 size is often well within the 5MB API limit), OR
  3. Show a meaningful error message instead of "No image found in clipboard"

Steps to Reproduce

  1. Copy any image with dimensions > 2000px to clipboard (e.g., a full-screen screenshot on a Retina display)
  2. Open Claude Code v2.1.98+
  3. Press Ctrl+V
  4. Expected: Image is pasted into the conversation
  5. Actual: Toast notification "No image found in clipboard"
  6. Workaround: Resize the image to ≤ 2000px before copying, then Ctrl+V works

Proposed Fixes

Fix 1 (Recommended): Pre-resize with sips on macOS before passing to sa():

// After reading the file, before calling sa():
if (process.platform === "darwin" && buf[0] === 0x89 && buf[1] === 0x50) {
  let w = buf.readUInt32BE(16), h = buf.readUInt32BE(20);
  if (w > maxWidth || h > maxHeight) {
    await exec(`sips --resampleWidth ${maxWidth} "${screenshotPath}"`);
    buf = fs.readFileSync(screenshotPath);
  }
}

Fix 2: Fix the bundled sharp so resize().toBuffer() works correctly in the bundle environment.

Fix 3: In the sa() catch block, fall back to returning the original image when base64 size is within the API limit, even if dimensions exceed the pixel limit:

// Current: throws when dimensions > limit AND sharp fails
if (base64Size <= maxBase64Size && !overDimensionLimit)
  return { buffer: original, mediaType };

// Proposed: also fall back when dimensions > limit but base64 is small enough
if (base64Size <= maxBase64Size)
  return { buffer: original, mediaType };

Error Messages/Logs

No image found in clipboard. Use ctrl+v to paste images.

(No error is logged — the exception is silently caught with catch { return null })

Is this a regression?

Yes, this worked in v2.1.97

Last Working Version

2.1.97

Claude Code Version

2.1.104

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Note: This is a different issue from #29776 (ENOBUFS / sandbox-exec). That issue affects ALL images regardless of size. This issue specifically affects only images > 2000px because it triggers the sharp resize code path which fails in the bundled environment.

View original on GitHub ↗

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