jackwener/OpenCLI · error · CommandExecutionError
WeChat image upload failed: ${message}
Error message
WeChat image upload failed: ${message} What it means
Thrown by injectImageFile when the primary upload path — setting the file input directly via page.setFileInput with the image's absolute path — fails with an error the library does not classify as recoverable. The original error message is wrapped into this CommandExecutionError.
Source
Thrown at clis/weixin/create-draft.js:121
return Array.from(editor.querySelectorAll('img')).map(function(img) {
return img.getAttribute('data-src') || img.getAttribute('src') || '';
}).filter(function(src) { return /(?:mmbiz|qpic\\.cn)/i.test(src); });
})()`);
if (!Array.isArray(keys)) {
throw new CommandExecutionError('WeChat image upload returned a malformed editor image payload.');
}
return keys.map(String);
}
async function injectImageFile(page, image) {
if (typeof page.setFileInput === 'function') {
try {
await page.setFileInput([image.absPath], IMAGE_FILE_INPUT_SELECTOR);
return;
} catch (error) {
if (!isRecoverableFileInputError(error)) {
const message = error instanceof Error ? error.message : String(error);
throw new CommandExecutionError(`WeChat image upload failed: ${message}`);
}
}
}
const base64 = fs.readFileSync(image.absPath).toString('base64');
const fallback = await evaluate(page, `(() => {
var input = document.querySelector(${JSON.stringify(IMAGE_FILE_INPUT_SELECTOR)});
if (!input) return { ok: false, reason: 'image file input not found' };
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' };View on GitHub (pinned to 49907e53dc)
Solutions
- Verify image.absPath exists and is a readable image file before calling the command.
- Ensure the upload dialog/file input is present before setFileInput runs (add a wait or poll for the input).
- Update or fix isRecoverableFileInputError if the underlying error should fall through to the base64 fallback path instead of throwing.
- Check the driver supports page.setFileInput with your image type; upgrade the automation driver if needed.
Example fix
// before
catch (error) {
if (!isRecoverableFileInputError(error)) {
const message = error instanceof Error ? error.message : String(error);
throw new CommandExecutionError(`WeChat image upload failed: ${message}`);
}
}
// after
catch (error) {
if (!isRecoverableFileInputError(error) && !isMissingFileInputError(error)) {
const message = error instanceof Error ? error.message : String(error);
throw new CommandExecutionError(`WeChat image upload failed: ${message}`);
}
// otherwise fall through to base64 evaluate() fallback
} Defensive patterns
Strategy: fallback
Validate before calling
const fs = require('fs');
if (!fs.existsSync(image.absPath)) throw new Error(`image missing: ${image.absPath}`);
if (fs.statSync(image.absPath).size === 0) throw new Error(`image is empty: ${image.absPath}`); Type guard
function hasSetFileInput(page) { return typeof page.setFileInput === 'function'; } Try / catch
try {
await createDraftCommand(opts);
} catch (e) {
if (/WeChat image upload failed:/i.test(e.message)) {
console.error('setFileInput path failed:', e.message);
// ensure image path/format are valid, then retry
}
throw e;
} Prevention
- Verify image files exist, are non-empty, and are JPEG/PNG before running.
- Keep the automation driver up to date so setFileInput semantics match.
- Ensure the upload dialog is open before file injection.
- Treat driver API changes (setFileInput) as a first suspect when this appears after an upgrade.
When it happens
Trigger: page.setFileInput throws because the file input selector (IMAGE_FILE_INPUT_SELECTOR) is absent, the input is hidden/detached, the driver lacks setFileInput support (but isRecoverableFileInputError deems the failure non-recoverable), or the image path is invalid and the driver rejects the file.
Common situations: WeChat changed the upload dialog's file input markup; the automation driver version lacks or changed setFileInput semantics; the image absPath points to a missing/unreadable file; the dialog did not open before the call.
Related errors
- WeChat image upload fallback failed: ${fallback?.reason || '
- WeChat image upload failed: ${state.errorText}
- WeChat image upload timed out before a new CDN image appeare
- Failed to fill title
- Failed to fill author
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a3919c7d3eb20220.
Report an issue: GitHub.