jackwener/OpenCLI · warning

[warn] Image base64 payload is ${(base64.length / 1024 / 102

Error message

[warn] Image base64 payload is ${(base64.length / 1024 / 1024).toFixed(1)}MB. This may fail with the browser bridge. Update the extension to v1.6+ for CDP-based upload, or compress the image before attaching.

What it means

attachComposerImage warns when the base64-encoded image read from disk exceeds ~500KB, because large payloads may fail when injected through the browser bridge's page.evaluate path. Older extensions (< v1.6) lack CDP-based upload, so big attachments can silently fail or time out.

Source

Thrown at clis/twitter/utils.js:155

            const msg = err instanceof Error ? err.message : String(err);
            if (!isRecoverableFileInputError(msg)) {
                throw new Error(`Image upload failed: ${msg}`);
            }
            // setFileInput not supported by extension — fall through to base64 fallback.
        }
    }
    if (!uploaded) {
        const ext = path.extname(absImagePath).toLowerCase();
        const mimeType = ext === '.png'
            ? 'image/png'
            : ext === '.gif'
                ? 'image/gif'
                : ext === '.webp'
                    ? 'image/webp'
                    : 'image/jpeg';
        const base64 = fs.readFileSync(absImagePath).toString('base64');
        if (base64.length > 500_000) {
            console.warn(`[warn] Image base64 payload is ${(base64.length / 1024 / 1024).toFixed(1)}MB. ` +
                'This may fail with the browser bridge. Update the extension to v1.6+ for CDP-based upload, ' +
                'or compress the image before attaching.');
        }
        const upload = await page.evaluate(`
      (() => {
        const input = document.querySelector(${JSON.stringify(fileInputSelector)});
        if (!input) return { ok: false, error: 'No file input found on page' };

        const binary = atob(${JSON.stringify(base64)});
        const bytes = new Uint8Array(binary.length);
        for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);

        const dt = new DataTransfer();
        const blob = new Blob([bytes], { type: ${JSON.stringify(mimeType)} });
        dt.items.add(new File([blob], ${JSON.stringify(path.basename(absImagePath))}, { type: ${JSON.stringify(mimeType)} }));

        let assigned = false;
        try {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the browser extension to v1.6+ for CDP-based upload which handles large payloads
  2. Compress/resize the image before attaching (e.g., convert to JPEG/WebP, scale to ≤1600px)
  3. If the attach then fails, retry after compressing rather than increasing timeouts
  4. Check the extension version in the browser and reload it if outdated

Example fix

// before
npx sharp -i photo.png -o photo-small.jpg resize 1280
opencli twitter attach-image photo-small.jpg
// after (compressed)
# attach the compressed file
opencli twitter attach-image photo-small.jpg
Defensive patterns

Strategy: validation

Validate before calling

const stat = fs.statSync(absImagePath);
if (stat.size > 375 * 1024) {
  console.warn('Image too large for browser bridge; compress first.');
}

Try / catch

try {
  await attachComposerImage(page, imagePath);
} catch (err) {
  if (err instanceof CliError && /upload|payload/i.test(err.message)) {
    await attachComposerImage(page, compressImage(imagePath)); // retry compressed
  }
}

Prevention

When it happens

Trigger: Attaching an image whose base64 string length > 500,000 characters (roughly a source file over ~375KB) via clis/twitter attach-image with a pre-v1.6 extension.

Common situations: Attaching high-resolution photos or uncompressed screenshots, GIFs several MB in size, older browser extension installed, images not pre-optimized before attach.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/852fa2997741e869. Report an issue: GitHub.