{"record":{"id":"0cc317865efcff45","repo":"jackwener/OpenCLI","slug":"provide-card-text-text-image-mode-or-images","errorCode":null,"errorMessage":"Provide --card-text (text-image mode) or --images (upload mode); neither was given.","messagePattern":"Provide --card-text \\(text-image mode\\) or --images \\(upload mode\\); neither was given\\.","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":1206,"sourceCode":"        const topics = kwargs.topics\n            ? String(kwargs.topics).split(',').map((s) => s.trim()).filter(Boolean)\n            : [];\n        const isDraft = Boolean(kwargs.draft);\n        const cardText = kwargs['card-text'] ? String(kwargs['card-text']) : '';\n        const cards = cardText\n            ? cardText.split(CARD_TEXT_DELIM).map((s) => s.trim()).filter(Boolean)\n            : [];\n        const cardStyle = kwargs['card-style'] ? String(kwargs['card-style']).trim() : '';\n        const isTextImage = cards.length > 0;\n        // ── Validate inputs ────────────────────────────────────────────────────────\n        if (!title)\n            throw new ArgumentError('--title is required');\n        if (title.length > MAX_TITLE_LEN)\n            throw new ArgumentError(`Title is ${title.length} chars — must be ≤ ${MAX_TITLE_LEN}`);\n        if (!content)\n            throw new ArgumentError('Positional argument <content> is required');\n        if (!isTextImage && imagePaths.length === 0)\n            throw new ArgumentError('Provide --card-text (text-image mode) or --images (upload mode); neither was given.');\n        if (imagePaths.length > MAX_IMAGES)\n            throw new ArgumentError(`Too many images: ${imagePaths.length} (max ${MAX_IMAGES})`);\n        // The editor-page image input (text-image append) rejects gif.\n        if (isTextImage && imagePaths.some((p) => path.extname(p).toLowerCase() === '.gif'))\n            throw new ArgumentError('文字配图模式追加的图片不支持 .gif（编辑器图片入口只接受 jpg/jpeg/png/webp）');\n        // Validate image paths before navigating (fast-fail on bad paths / unsupported formats)\n        const absImagePaths = validateImagePaths(imagePaths);\n        // ── Step 1: Navigate to publish page ──────────────────────────────────────\n        await page.goto(PUBLISH_URL);\n        await page.wait({ time: 3 });\n        // Verify we landed on the creator site (not redirected to login)\n        const pageUrl = await page.evaluate('() => location.href');\n        if (!pageUrl.includes('creator.xiaohongshu.com')) {\n            throw new Error('Redirected away from creator center — session may have expired. ' +\n                'Re-capture browser login via: opencli xiaohongshu creator-profile');\n        }\n        // ── Step 2: Select 图文 (image+text) note type if tabs are present ─────────\n        const tabResult = await selectImageTextTab(page);","sourceCodeStart":1188,"sourceCodeEnd":1224,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L1188-L1224","documentation":"ArgumentError thrown when neither publish mode was supplied: no --card-text (text-image/文字配图 mode) and no --images (upload mode). The command requires exactly one of these two content sources and refuses to continue otherwise.","triggerScenarios":"Running publish with --title and content but omitting both --card-text and --images, so isTextImage is false and imagePaths.length === 0.","commonSituations":"Thinking content alone is enough to publish (XHS requires at least one image or generated card images); misspelling the flags (--image, --cards); shell quoting causing the flag value to be parsed away.","solutions":["Add --card-text \"第一张|第二张\" for text-image mode, or","Add --images \"a.jpg,b.png\" for upload mode","Check flag spelling — the flags are exactly --card-text and --images"],"exampleFix":"// before\nnode publish.js --title \"标题\" \"正文\"\n// after\nnode publish.js --title \"标题\" \"正文\" --images \"./pic1.jpg,./pic2.jpg\"","handlingStrategy":"validation","validationCode":"const hasImages = imagesFlag && imagesFlag.trim().length > 0;\nconst hasCards = cardTextFlag && cardTextFlag.trim().length > 0;\nif (!hasImages && !hasCards) throw new Error('Provide --card-text or --images');","typeGuard":"function hasPublishSource(kwargs) {\n  return Boolean(\n    (kwargs.images && String(kwargs.images).trim()) ||\n    (kwargs['card-text'] && String(kwargs['card-text']).trim())\n  );\n}","tryCatchPattern":"try {\n  await publish(page, kwargs);\n} catch (e) {\n  if (String(e.message).includes('neither was given')) {\n    console.error('Add --card-text \"a|b\" (text-image) or --images \"1.jpg,2.jpg\" (upload)');\n  }\n  throw e;\n}","preventionTips":["Decide the mode (text-image vs upload) before composing the command","Check exact flag spellings: --card-text and --images","Dry-run validation of the full argument set in CI wrappers"],"tags":["validation","cli-arguments","xiaohongshu"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}