jackwener/OpenCLI · error · CommandExecutionError

WeChat image upload fallback failed: ${fallback?.reason || '

Error message

WeChat image upload fallback failed: ${fallback?.reason || 'unknown error'}

What it means

Thrown by injectImageFile when the primary setFileInput path could not run and the fallback path — reading the image as base64 and injecting it via an in-page evaluate() upload — reports failure via { ok: false, reason }. The reason string from the in-page script is embedded in the error message.

Source

Thrown at clis/weixin/create-draft.js:148

        try {
            var binary = atob(${JSON.stringify(base64)});
            var bytes = new Uint8Array(binary.length);
            for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
            var transfer = new DataTransfer();
            transfer.items.add(new File([bytes], ${JSON.stringify(image.fileName)}, { type: ${JSON.stringify(image.mimeType)} }));
            var descriptor = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'files');
            if (descriptor && descriptor.set) descriptor.set.call(input, transfer.files);
            else input.files = transfer.files;
            if (!input.files || input.files.length !== 1) return { ok: false, reason: 'file input rejected fallback file' };
            input.dispatchEvent(new Event('input', { bubbles: true }));
            input.dispatchEvent(new Event('change', { bubbles: true }));
            return { ok: true };
        } catch (error) {
            return { ok: false, reason: String(error && error.message || error) };
        }
    })()`);
    if (!fallback?.ok) {
        throw new CommandExecutionError(`WeChat image upload fallback failed: ${fallback?.reason || 'unknown error'}`);
    }
}

async function uploadContentImage(page, image) {
    const previousKeys = await readCdnImageKeys(page);
    const opened = await evaluate(page, `(() => {
        var button = document.querySelector('#js_editor_insertimage');
        if (!button) return { ok: false, reason: 'insert-image button not found' };
        button.click();
        return { ok: true };
    })()`);
    if (!opened?.ok) throw new CommandExecutionError(`Could not open WeChat image upload: ${opened?.reason || 'unknown error'}`);
    await page.wait(1);

    const selected = await evaluate(page, `(() => {
        var item = document.querySelector('.js_img_dropdown_menu .tpl_dropdown_menu_item');
        if (!item) return { ok: false, reason: 'upload menu item not found' };
        item.click();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Compress/resize the image (e.g. <1MB, JPEG/PNG) before running the command so base64 injection fits within limits.
  2. Ensure the upload dialog is fully open before the fallback runs (add a wait/poll for the file input).
  3. Inspect fallback.reason in the error message — it names the underlying in-page failure — and fix that specific cause.
  4. Prefer fixing the primary setFileInput path so the fragile base64 fallback is never needed.

Example fix

// before
const base64 = fs.readFileSync(image.absPath).toString('base64');
// after
const stats = fs.statSync(image.absPath);
if (stats.size > 2 * 1024 * 1024) {
    image.absPath = await compressImage(image.absPath, { maxBytes: 2 * 1024 * 1024 });
}
const base64 = fs.readFileSync(image.absPath).toString('base64');
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const MAX = 2 * 1024 * 1024;
const size = fs.statSync(image.absPath).size;
if (size > MAX) throw new Error(`image too large for base64 fallback (${size} bytes); compress below 2MB`);
if (!/\.(jpe?g|png|gif)$/i.test(image.absPath)) throw new Error('convert image to JPEG/PNG/GIF before upload');

Type guard

function isUploadResult(v) { return typeof v === 'object' && v !== null && typeof v.ok === 'boolean'; }

Try / catch

try {
    await createDraftCommand(opts);
} catch (e) {
    if (/image upload fallback failed/i.test(e.message)) {
        console.error('fallback reason:', e.message); // reason names the in-page failure
    }
    throw e;
}

Prevention

When it happens

Trigger: The base64 image is too large for the evaluate bridge or the page, the in-page script cannot find the file input to populate, the page context threw (input missing, dialog closed, CSP or driver restrictions on large strings), or the image is not a format WeChat accepts.

Common situations: Very large images (multi-MB) blowing up evaluate string limits; base64 fallback running before the upload dialog opened; driver restrictions on evaluating large payloads; image format issues (e.g. webp) rejected by the page script.

Related errors


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