{"record":{"id":"8741f084ecc773c9","repo":"jackwener/OpenCLI","slug":"douyin-hashtag-suggest-cover-cover-uri","errorCode":null,"errorMessage":"douyin hashtag suggest 需要 --cover <cover_uri>","messagePattern":"douyin hashtag suggest 需要 --cover <cover_uri>","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/douyin/hashtag.js","lineNumber":37,"sourceCode":"}\n\nfunction validateHashtagArgs(kwargs) {\n    const action = kwargs.action;\n    const limit = Number(kwargs.limit ?? 10);\n    if (!Number.isInteger(limit) || limit < 1) {\n        throw new ArgumentError(`--limit must be a positive integer, got ${JSON.stringify(kwargs.limit)}`);\n    }\n    if (action === 'search') {\n        const keyword = String(kwargs.keyword ?? '').trim();\n        if (!keyword) {\n            throw new ArgumentError('douyin hashtag search 需要 --keyword <关键词>', '示例: opencli douyin hashtag search --keyword 美食');\n        }\n        return;\n    }\n    if (action === 'suggest') {\n        const cover = String(kwargs.cover ?? '').trim();\n        if (!cover) {\n            throw new ArgumentError('douyin hashtag suggest 需要 --cover <cover_uri>', 'suggest 基于已上传的视频封面做 AI 推荐, 不是关键词搜索. 关键词搜索请用 `douyin hashtag search --keyword <词>`.');\n        }\n    }\n}\n\ncli({\n    site: 'douyin',\n    name: 'hashtag',\n    access: 'read',\n    description: '话题搜索 / AI推荐 / 热点词',\n    domain: 'creator.douyin.com',\n    strategy: Strategy.COOKIE,\n    args: [\n        { name: 'action', required: true, positional: true, choices: ['search', 'suggest', 'hot'], help: 'search=关键词搜索 (--keyword 必填), suggest=AI推荐 (--cover 必填), hot=热点词 (--keyword 可选)' },\n        { name: 'keyword', default: '', help: '搜索关键词. search 必填; hot 可选; suggest 不使用 (传 --cover)' },\n        { name: 'cover', default: '', help: '封面 URI (cover_uri). suggest 必填; 其它 action 不使用' },\n        { name: 'limit', type: 'int', default: 10 },\n    ],\n    columns: ['name', 'id', 'view_count'],","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/hashtag.js#L19-L55","documentation":"The `suggest` action recommends hashtags from an already-uploaded video cover URI and therefore requires --cover. validateHashtagArgs throws an ArgumentError (with guidance pointing keyword searches to the `search` action) when the cover value is empty after trimming.","triggerScenarios":"Running `douyin hashtag suggest` without `--cover <cover_uri>`, with an empty string, or with whitespace-only input; also using suggest when the user actually wanted keyword search.","commonSituations":"Mixing up the two actions (search vs suggest), not having uploaded the video yet so no cover_uri exists, or scripts passing an unset cover variable.","solutions":["Pass the cover URI from a previously uploaded video: `douyin hashtag suggest --cover <cover_uri>`","If you want keyword-based lookup, use `douyin hashtag search --keyword <词>` instead","Upload the video (or run the draft flow) first to obtain a cover_uri, then call suggest"],"exampleFix":"// before\nopencli douyin hashtag suggest  // missing cover\n// after\nopencli douyin hashtag suggest --cover \"douyin://cover/xxxx\"","handlingStrategy":"validation","validationCode":"const cover = (process.env.COVER_URI ?? '').trim();\nif (!cover) throw new Error('suggest requires --cover <cover_uri>; use search --keyword for text lookup');","typeGuard":"const hasCover = (c) => typeof c === 'string' && c.trim().length > 0;","tryCatchPattern":"try {\n  await cli.hashtag({ action: 'suggest', cover });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('suggest 需要 --cover')) {\n    await cli.hashtag({ action: 'search', keyword: fallbackKeyword });\n  } else throw e;\n}","preventionTips":["Complete the video upload/draft flow first so a cover_uri exists","Default to the search action when you only have a keyword, not a cover","Guard cover variables in scripts with ${COVER:?msg} to fail fast"],"tags":["validation","argument-error","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}