jackwener/OpenCLI · error · CommandExecutionError

WeChat image upload failed: ${state.errorText}

Error message

WeChat image upload failed: ${state.errorText}

What it means

Thrown by uploadContentImage during the post-upload polling loop when the page reports an error text (errorText) matching WeChat's known upload failure patterns (无法解析/cannot parse, 上传失败/upload failed, 过大/too large, 频繁/too frequent, 不支持/unsupported, 错误/error). The raw WeChat error text is embedded in the message.

Source

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

    for (let attempt = 0; attempt < 15; attempt++) {
        await page.wait(2);
        const state = await evaluate(page, `(() => {
            var previous = new Set(${JSON.stringify(previousKeys)});
            var editor = document.querySelector('#ueditor_0');
            var images = editor ? Array.from(editor.querySelectorAll('img')) : [];
            var key = images.map(function(img) {
                return img.getAttribute('data-src') || img.getAttribute('src') || '';
            }).find(function(src) { return /(?:mmbiz|qpic\\.cn)/i.test(src) && !previous.has(src); });
            var errorText = Array.from(document.querySelectorAll('.weui-desktop-tips, .weui-desktop-toast, .js_msgSenderTips'))
                .filter(function(el) { return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); })
                .map(function(el) { return (el.innerText || el.textContent || '').trim(); })
                .filter(Boolean).join('\\n');
            return { ok: !!key, errorText: errorText };
        })()`);
        if (state?.ok) return;
        if (state?.errorText && /(无法解析|上传失败|过大|频繁|不支持|错误)/.test(state.errorText)) {
            throw new CommandExecutionError(`WeChat image upload failed: ${state.errorText}`);
        }
    }
    throw new CommandExecutionError('WeChat image upload timed out before a new CDN image appeared in the editor.');
}

async function selectCoverFromContent(page) {
    await evaluate(page, 'document.querySelector("#js_cover_description_area")?.scrollIntoView()');
    await page.wait(1);
    await evaluate(page, 'document.querySelector(".js_cover_btn_area")?.click()');
    await page.wait(1);
    await evaluate(page, `(() => {
        var link = Array.from(document.querySelectorAll('a.pop-opr__button')).find(function(el) {
            return (el.textContent || '').trim() === '从正文选择';
        });
        if (link) link.click();
    })()`);
    await page.wait(2);
    await evaluate(page, `document.querySelector('.weui-desktop-dialog_img-picker .appmsg_content_img')?.click()`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the embedded WeChat error text: resize/compress the image if it says 过大, convert to JPEG/PNG if 不支持, or wait before retrying if 频繁.
  2. Validate the image file locally (size, format, integrity) before running the command.
  3. Add a delay/backoff between uploads or between command runs to avoid WeChat's rate limit.
  4. Retry once after a pause if the error text indicates a transient server-side 错误.

Example fix

// before
await uploadContentImage(page, image);
// after
const stats = fs.statSync(image.absPath);
if (stats.size > 10 * 1024 * 1024) {
    image.absPath = await compressImage(image.absPath, { maxBytes: 10 * 1024 * 1024, format: 'jpeg' });
}
await sleep(5000); // avoid 频繁 rate limit
await uploadContentImage(page, image);
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const MAX_BYTES = 10 * 1024 * 1024;
const size = fs.statSync(image.absPath).size;
if (size > MAX_BYTES) throw new Error(`image ${image.absPath} is ${size} bytes; WeChat limit exceeded — compress first`);
if (!/\.(jpe?g|png|gif)$/i.test(image.absPath)) throw new Error('unsupported format; convert to JPEG/PNG/GIF');

Type guard

function isUploadState(v) { return typeof v === 'object' && v !== null && ('ok' in v) && ('errorText' in v); }

Try / catch

try {
    await createDraftCommand(opts);
} catch (e) {
    if (/WeChat image upload failed: (.+)/.test(e.message)) {
        const wechatError = e.message.match(/WeChat image upload failed: (.+)/)[1];
        if (/频繁/.test(wechatError)) { await sleep(60000); /* retry after rate limit */ }
        else if (/过大|不支持|无法解析/.test(wechatError)) { /* fix image locally before retry */ }
    }
    throw e;
}

Prevention

When it happens

Trigger: The uploaded image exceeds WeChat's size limit (过大), the image format is unsupported (不支持), uploads are rate-limited (频繁), the image cannot be parsed (无法解析), or WeChat's upload endpoint returned an error shown in the dialog.

Common situations: Uploading images over ~10MB or with unsupported formats (BMP, very large PNGs); batch-running the command many times in a row triggering rate limiting; corrupted or zero-byte image files; temporary WeChat server-side upload errors.

Related errors


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