{"record":{"id":"2935f726292fbe45","repo":"jackwener/OpenCLI","slug":"douyin-search-query","errorCode":null,"errorMessage":"douyin search 需要 <query> 关键词","messagePattern":"douyin search 需要 <query> 关键词","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/douyin/search.js","lineNumber":269,"sourceCode":"}\n\ncli({\n    site: 'douyin',\n    name: 'search',\n    access: 'read',\n    description: '关键词搜索抖音视频',\n    domain: 'www.douyin.com',\n    strategy: Strategy.COOKIE,\n    args: [\n        { name: 'query', required: true, positional: true, help: '搜索关键词' },\n        { name: 'limit', type: 'int', default: 10, help: `结果数量 (1-${MAX_SEARCH_LIMIT})` },\n    ],\n    columns: ['rank', 'desc', 'author', 'url', 'plays', 'likes', 'comments', 'shares'],\n    func: async (page, kwargs) => {\n        const limit = parseSearchLimit(kwargs.limit);\n        const keyword = String(kwargs.query ?? '').trim();\n        if (!keyword) {\n            throw new ArgumentError('douyin search 需要 <query> 关键词');\n        }\n        await page.goto(`https://www.douyin.com/search/${encodeURIComponent(keyword)}?type=video`);\n        let result;\n        try {\n            result = unwrapEvaluateResult(await page.evaluate(WAIT_AND_EXTRACT_JS(RENDER_TIMEOUT_MS)));\n        } catch (error) {\n            throw new CommandExecutionError(`Douyin search extraction failed: ${error instanceof Error ? error.message : String(error)}`);\n        }\n        if (!result || typeof result !== 'object') {\n            throw new CommandExecutionError('Douyin search: unexpected evaluator payload shape');\n        }\n        if (result.state === 'login_wall') {\n            throw new AuthRequiredError(\n                'www.douyin.com',\n                'Douyin search results are blocked behind a login wall — log in at https://www.douyin.com in Chrome first.',\n            );\n        }\n        if (result.state === 'empty') {","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/search.js#L251-L287","documentation":"The douyin search command requires a query keyword. It reads kwargs.query, trims it, and throws this ArgumentError when the result is empty. Without a keyword there is no search URL to navigate to (https://www.douyin.com/search/<keyword>?type=video), so the command fails fast before touching the browser.","triggerScenarios":"Invoking search with no --query flag, an empty string (''), or whitespace-only ('   ') value — kwargs.query ?? '' .trim() then evaluates falsy.","commonSituations":"Scripts building the command from variables where the query came from an empty env var or CLI arg; users passing only --limit or filters; template invocations with an unfilled placeholder.","solutions":["Provide a non-empty query: douyin search --query \"cats\"","Trim/validate the query in the calling script before invoking the command","Fail early with a clear usage message when the upstream variable is empty"],"exampleFix":"// before\nconst q = process.env.QUERY ?? '';\nawait douyin.search({ query: q, limit: 10 });\n// after\nconst q = (process.env.QUERY ?? '').trim();\nif (!q) throw new Error('QUERY env var is required');\nawait douyin.search({ query: q, limit: 10 });","handlingStrategy":"validation","validationCode":"const query = String(kwargs.query ?? '').trim();\nif (!query) {\n  throw new Error('usage: douyin search --query <keyword>');\n}","typeGuard":"function hasQuery(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  await douyin.search({ query: rawQuery, limit });\n} catch (e) {\n  if (e instanceof ArgumentError && /需要 <query> 关键词/.test(e.message)) {\n    console.error('A non-empty --query is required');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Trim and check query variables before building command invocations","Give clear usage errors in wrapper scripts when env vars are empty","Make --query required at your own CLI layer so the error never surfaces"],"tags":["validation","argument-error","cli"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}