jackwener/OpenCLI · error · CommandExecutionError
${label}: expected at least ${expectedCount} visible media i
Error message
${label}: expected at least ${expectedCount} visible media item(s), got ${state.count}. Debug screenshot: /tmp/xhs_publish_media_debug.png What it means
assertComposerMediaCount verified the count successfully but found fewer visible media items than expected. It saves a debug screenshot to /tmp/xhs_publish_media_debug.png and throws with both counts. This is a write-postcondition guard so media uploads that silently failed are caught before publishing.
Source
Thrown at clis/xiaohongshu/publish.js:1042
const key = src || String(Math.round(rect.left)) + ':' + String(Math.round(rect.top));
if (seen.has(key)) continue;
seen.add(key);
count += 1;
}
}
return { ok: true, count };
})()
`);
return unwrapBrowserResult(result);
}
async function assertComposerMediaCount(page, expectedCount, label) {
const state = await currentComposerMediaCount(page);
if (!state || typeof state.count !== 'number') {
throw new CommandExecutionError(`${label}: could not verify current composer media count`);
}
if (state.count < expectedCount) {
await page.screenshot({ path: '/tmp/xhs_publish_media_debug.png' });
throw new CommandExecutionError(`${label}: expected at least ${expectedCount} visible media item(s), got ${state.count}. ` +
'Debug screenshot: /tmp/xhs_publish_media_debug.png');
}
}
/**
* Drive the full 文字配图 sub-flow: entry → type cards → 生成图片 → pick style → 下一步.
* Leaves the page on the standard editor (caller then runs waitForEditForm).
*/
async function runTextImageFlow(page, cards, cardStyle) {
const entry = await clickByText(page, TEXT_IMAGE_ENTRY_LABEL);
if (!entry?.ok) {
await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
throw new CommandExecutionError(`文字配图: could not click "${TEXT_IMAGE_ENTRY_LABEL}" entry. ` +
'Debug: /tmp/xhs_publish_textimage_debug.png');
}
if (!(await waitForFirstCard(page))) {
await page.screenshot({ path: '/tmp/xhs_publish_textimage_debug.png' });
throw new CommandExecutionError(`文字配图: 写文字 card editor did not appear after clicking "${TEXT_IMAGE_ENTRY_LABEL}". ` +
'Debug: /tmp/xhs_publish_textimage_debug.png');View on GitHub (pinned to 49907e53dc)
Solutions
- Open /tmp/xhs_publish_media_debug.png to see what the composer actually shows and which media is missing.
- Retry the publish with longer waits between uploads so processing finishes before assertion.
- Validate images before upload (format, size limits) and reduce count if exceeding XHS's max (e.g. 18 for image posts).
- Re-upload the failed media; if one specific image always fails, re-encode it (JPEG, within size limit).
Example fix
// before
await uploadMedia(page, images);
await assertComposerMediaCount(page, images.length, "发布");
// after
for (const img of images) {
await uploadOne(page, img);
await page.wait({ time: 1.5 }); // let thumbnail render
}
await assertComposerMediaCount(page, images.length, "发布"); Defensive patterns
Strategy: validation
Validate before calling
// check each image before upload
for (const img of images) {
const kb = fs.statSync(img).size / 1024;
if (kb > 32000) throw new Error(`${img} exceeds XHS size limit`);
if (!/\.(jpe?g|png|webp)$/i.test(img)) throw new Error(`${img} unsupported format`);
}
if (images.length > 18) throw new Error('XHS allows max 18 images per post'); Type guard
null
Try / catch
try { await assertComposerMediaCount(page, images.length, '发布'); }
catch (e) {
if (/expected at least/.test(e.message)) {
console.error('Check debug screenshot: /tmp/xhs_publish_media_debug.png');
// re-upload missing media and re-assert
} else throw e;
} Prevention
- Pre-validate image format, size, and count against XHS limits
- Wait between uploads so thumbnails render before counting
- Always inspect the debug screenshot path in the message
When it happens
Trigger: state.count < expectedCount after uploading media: one or more uploads failed silently, media still processing/not yet rendered in the composer, or a duplicate/blank upload was dropped by XHS.
Common situations: Large images timing out during upload; network throttling so thumbnails haven't rendered within the wait window; XHS rejecting an image (format/size) without surfacing an error; uploading more images than XHS's limit.
Related errors
- Instagram private publish upload failed for ${prepared.asset
- Failed to upload image to ChatGPT: ${err instanceof Error ?
- Failed to upload image to ChatGPT
- Failed to upload file to ChatGPT project knowledge: ${err in
- Failed to upload file to ChatGPT project knowledge
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/474abc2bfc863af7.
Report an issue: GitHub.