jackwener/OpenCLI · error · CommandExecutionError
WeChat image upload timed out before a new CDN image appeare
Error message
WeChat image upload timed out before a new CDN image appeared in the editor.
What it means
Thrown by uploadContentImage when the 15-attempt polling loop (each with a 2-second wait) completes without detecting a new mmbiz/qpic CDN image key in the editor and without any recognized WeChat error text. The upload neither succeeded nor produced a page-reported error within ~30 seconds.
Source
Thrown at clis/weixin/create-draft.js:193
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()`);
await page.wait(1);
await evaluate(page, `(() => {
var button = Array.from(document.querySelectorAll('.weui-desktop-dialog_img-picker button')).find(function(el) {View on GitHub (pinned to 49907e53dc)
Solutions
- Retry with a smaller/compressed image to reduce upload time below the 30-second polling budget.
- Check the network connection and WeChat service status; transient slowness can exceed the polling window.
- Verify the success-detection script still matches how WeChat inserts uploaded images (img src/data-src with mmbiz/qpic) and update if the editor changed.
- Increase the poll attempt count or interval for large images or slow environments.
Example fix
// before
for (let attempt = 0; attempt < 15; attempt++) {
await page.wait(2);
...
}
// after
const maxAttempts = process.env.WEIXIN_UPLOAD_POLL_ATTEMPTS ? Number(process.env.WEIXIN_UPLOAD_POLL_ATTEMPTS) : 15;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
await page.wait(2);
...
} Defensive patterns
Strategy: retry
Validate before calling
const fs = require('fs');
if (fs.statSync(image.absPath).size > 5 * 1024 * 1024) throw new Error('image too large; upload may exceed the 30s detection window — compress first'); Type guard
function isPollState(v) { return typeof v === 'object' && v !== null && ('ok' in v); } Try / catch
try {
await createDraftCommand(opts);
} catch (e) {
if (/timed out before a new CDN image/i.test(e.message)) {
await sleep(10000);
return createDraftCommand(opts); // retry once with a pause
}
throw e;
} Prevention
- Keep images small so uploads finish within the ~30s polling budget.
- Ensure a stable network connection; avoid running on flaky CI networks.
- Retry once after a pause before investigating deeper.
- Check the CDN-key detection selectors still match WeChat's inserted <img> markup.
When it happens
Trigger: The upload dialog silently closed, the file injection never actually started an upload, the upload is genuinely slow (large image, slow network) and exceeds the ~30s budget, or the success detection (new CDN key appearing in the editor) fails because WeChat changed how uploaded images are inserted into the DOM.
Common situations: Slow networks or large images exceeding the timeout; WeChat editor updates changing the img data-src/src attributes the detection script inspects; headless environments where the upload silently stalls.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- 等待抖音草稿编辑页超时
- Instagram reel preview did not appear after upload
- 视频上传/转码超时(${Math.ceil(maxMs / 1000)}秒),请检查网络或稍后重试
- WeChat image upload failed: ${message}
- WeChat image upload fallback failed: ${fallback?.reason || '
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/20966c3bf35af34f.
Report an issue: GitHub.