{"record":{"id":"87f1679a3be74172","repo":"jackwener/OpenCLI","slug":"wechat-image-upload-failed-state-errortext","errorCode":null,"errorMessage":"WeChat image upload failed: ${state.errorText}","messagePattern":"WeChat image upload failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/weixin/create-draft.js","lineNumber":190,"sourceCode":"\n    for (let attempt = 0; attempt < 15; attempt++) {\n        await page.wait(2);\n        const state = await evaluate(page, `(() => {\n            var previous = new Set(${JSON.stringify(previousKeys)});\n            var editor = document.querySelector('#ueditor_0');\n            var images = editor ? Array.from(editor.querySelectorAll('img')) : [];\n            var key = images.map(function(img) {\n                return img.getAttribute('data-src') || img.getAttribute('src') || '';\n            }).find(function(src) { return /(?:mmbiz|qpic\\\\.cn)/i.test(src) && !previous.has(src); });\n            var errorText = Array.from(document.querySelectorAll('.weui-desktop-tips, .weui-desktop-toast, .js_msgSenderTips'))\n                .filter(function(el) { return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); })\n                .map(function(el) { return (el.innerText || el.textContent || '').trim(); })\n                .filter(Boolean).join('\\\\n');\n            return { ok: !!key, errorText: errorText };\n        })()`);\n        if (state?.ok) return;\n        if (state?.errorText && /(无法解析|上传失败|过大|频繁|不支持|错误)/.test(state.errorText)) {\n            throw new CommandExecutionError(`WeChat image upload failed: ${state.errorText}`);\n        }\n    }\n    throw new CommandExecutionError('WeChat image upload timed out before a new CDN image appeared in the editor.');\n}\n\nasync function selectCoverFromContent(page) {\n    await evaluate(page, 'document.querySelector(\"#js_cover_description_area\")?.scrollIntoView()');\n    await page.wait(1);\n    await evaluate(page, 'document.querySelector(\".js_cover_btn_area\")?.click()');\n    await page.wait(1);\n    await evaluate(page, `(() => {\n        var link = Array.from(document.querySelectorAll('a.pop-opr__button')).find(function(el) {\n            return (el.textContent || '').trim() === '从正文选择';\n        });\n        if (link) link.click();\n    })()`);\n    await page.wait(2);\n    await evaluate(page, `document.querySelector('.weui-desktop-dialog_img-picker .appmsg_content_img')?.click()`);","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weixin/create-draft.js#L172-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the embedded WeChat error text: resize/compress the image if it says 过大, convert to JPEG/PNG if 不支持, or wait before retrying if 频繁.","Validate the image file locally (size, format, integrity) before running the command.","Add a delay/backoff between uploads or between command runs to avoid WeChat's rate limit.","Retry once after a pause if the error text indicates a transient server-side 错误."],"exampleFix":"// before\nawait uploadContentImage(page, image);\n// after\nconst stats = fs.statSync(image.absPath);\nif (stats.size > 10 * 1024 * 1024) {\n    image.absPath = await compressImage(image.absPath, { maxBytes: 10 * 1024 * 1024, format: 'jpeg' });\n}\nawait sleep(5000); // avoid 频繁 rate limit\nawait uploadContentImage(page, image);","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst MAX_BYTES = 10 * 1024 * 1024;\nconst size = fs.statSync(image.absPath).size;\nif (size > MAX_BYTES) throw new Error(`image ${image.absPath} is ${size} bytes; WeChat limit exceeded — compress first`);\nif (!/\\.(jpe?g|png|gif)$/i.test(image.absPath)) throw new Error('unsupported format; convert to JPEG/PNG/GIF');","typeGuard":"function isUploadState(v) { return typeof v === 'object' && v !== null && ('ok' in v) && ('errorText' in v); }","tryCatchPattern":"try {\n    await createDraftCommand(opts);\n} catch (e) {\n    if (/WeChat image upload failed: (.+)/.test(e.message)) {\n        const wechatError = e.message.match(/WeChat image upload failed: (.+)/)[1];\n        if (/频繁/.test(wechatError)) { await sleep(60000); /* retry after rate limit */ }\n        else if (/过大|不支持|无法解析/.test(wechatError)) { /* fix image locally before retry */ }\n    }\n    throw e;\n}","preventionTips":["Pre-compress images well under WeChat's size limit.","Convert all images to JPEG/PNG before upload.","Throttle command runs to avoid WeChat's 频繁 rate limit.","Parse the embedded Chinese error text to choose the right remediation."],"tags":["wechat","image","upload-limit","rate-limit"],"backgroundTag":"upload-size-limit-exceeded","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}