{"record":{"id":"0b85521602386630","repo":"jackwener/OpenCLI","slug":"appending-images-failed-upload-error-unknow","errorCode":null,"errorMessage":"Appending images failed: ${upload.error ?? 'unknown'}. Debug screenshot: /tmp/xhs_publish_append_debug.png","messagePattern":"Appending images failed: (.+?)\\. Debug screenshot: /tmp/xhs_publish_append_debug\\.png","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":1265,"sourceCode":"            await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });\n            await waitForUploads(page);\n        }\n        // ── Step 3b: Wait for editor form to render ───────────────────────────────\n        const formReady = await waitForEditForm(page);\n        if (!formReady) {\n            await page.screenshot({ path: '/tmp/xhs_publish_form_debug.png' });\n            throw new CommandExecutionError('Editing form did not appear after image acquisition. The page layout may have changed. ' +\n                'Debug screenshot: /tmp/xhs_publish_form_debug.png');\n        }\n        if (isTextImage) {\n            await assertComposerMediaCount(page, cards.length, '文字配图 generated images');\n        }\n        // ── Step 3c: In text-image mode, optionally append uploaded images ────────\n        if (isTextImage && absImagePaths.length > 0) {\n            const upload = await uploadImages(page, absImagePaths);\n            if (!upload.ok) {\n                await page.screenshot({ path: '/tmp/xhs_publish_append_debug.png' });\n                throw new CommandExecutionError(`Appending images failed: ${upload.error ?? 'unknown'}. ` +\n                    'Debug screenshot: /tmp/xhs_publish_append_debug.png');\n            }\n            await page.wait({ time: UPLOAD_SETTLE_MS / 1_000 });\n            await waitForUploads(page);\n            await assertComposerMediaCount(page, cards.length + absImagePaths.length, '文字配图 appended images');\n        }\n        // ── Step 4: Fill title ─────────────────────────────────────────────────────\n        await fillField(page, TITLE_SELECTORS, title, 'title');\n        await page.wait({ time: 0.5 });\n        // ── Step 5: Fill content / body ────────────────────────────────────────────\n        await fillField(page, BODY_SELECTORS, content, 'content');\n        await page.wait({ time: 0.5 });\n        // ── Step 6: Add topic hashtags ─────────────────────────────────────────────\n        // XHS converts a \"#keyword\" typed into the body editor into a real topic\n        // entity only when the user picks an item from the inline suggestion\n        // dropdown that pops up while typing. The previous implementation looked\n        // for a standalone \"添加话题\" button + dedicated search <input>, which the\n        // current creator-center editor no longer exposes — it left bare \"#\"","sourceCodeStart":1247,"sourceCodeEnd":1283,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L1247-L1283","documentation":"In 文字配图 (text-image) mode, after generated cards are applied, any additional --images files are appended via uploadImages. If that append upload fails, the CLI screenshots the page and aborts with the underlying upload error.","triggerScenarios":"isTextImage is true and absImagePaths.length > 0, and the second uploadImages call returns { ok:false } — file missing/unreadable, input selector changed, or injection rejected.","commonSituations":"Same causes as the initial upload error: bad/relative image paths, unsupported format, deleted files, or composer DOM changes — but hit only when combining generated cards with extra uploaded images.","solutions":["Read the upload.error detail and check /tmp/xhs_publish_append_debug.png.","Verify each appended image path exists, is absolute, and is a supported format.","Retry the command; transient injection races occur.","If only generated cards are needed, drop the --images flag to bypass the append step."],"exampleFix":"// before\nopencli xiaohongshu publish --text-image --images missing.png\n// after\nls -l missing.png   # verify first, or omit --images to use generated cards only","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst appendPaths = opts.images || [];\nfor (const p of appendPaths) {\n  if (!fs.existsSync(p)) throw new Error(`Append image not found: ${p}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await publish({ textImage: true, images: extra });\n} catch (e) {\n  if (String(e.message).startsWith('Appending images failed')) {\n    // fall back to generated cards only\n    return publish({ textImage: true });\n  }\n  throw e;\n}","preventionTips":["Verify appended image paths exist and are absolute before invoking.","Use supported image formats for appended files.","If extra uploads aren't essential, omit --images in text-image mode.","Check /tmp/xhs_publish_append_debug.png for recurring failures."],"tags":["file-upload","io","browser-automation","xiaohongshu"],"backgroundTag":"file-upload-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}