{"record":{"id":"b8250a2b393a32d0","repo":"jackwener/OpenCLI","slug":"douyin-search","errorCode":null,"errorMessage":"douyin search","messagePattern":"douyin search","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/douyin/search.js","lineNumber":297,"sourceCode":"            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') {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        if (result.state === 'timeout') {\n            throw new CommandExecutionError('Douyin search did not render result cards within the timeout. Open the same search in Chrome and verify login/security state before retrying.');\n        }\n        if (!Array.isArray(result.cards)) {\n            throw new CommandExecutionError('Douyin search: evaluator returned malformed cards payload');\n        }\n        if (result.cards.length === 0) {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        const projected = projectSearchCards(result.cards, limit);\n        if (projected.invalidCount > 0) {\n            throw new CommandExecutionError('Douyin search parser found result cards without stable video url or description');\n        }\n        if (projected.rows.length === 0) {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        return projected.rows;\n    },\n});\n","sourceCodeStart":279,"sourceCodeEnd":309,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/search.js#L279-L309","documentation":"The string 'douyin search' here is the scope/resource argument of an EmptyResultError, not the message: it identifies which command produced the empty outcome. It is thrown when result.cards is an empty array — the page rendered, the user is logged in, but the extractor found zero result rows.","triggerScenarios":"Evaluator collected no <li> rows inside [data-e2e=scroll-list]: query genuinely has no results, or Douyin changed the container markup so the selector matches nothing while state still reports ok.","commonSituations":"Douyin DOM churn renaming data-e2e hooks; keyword with zero matches; region-locked results hidden for the session's locale.","solutions":["Open the search in the bound browser to see if cards visibly render; if they do, the selector hook changed and needs updating.","Retry with a common keyword to distinguish a real empty result from selector rot.","Treat EmptyResultError with scope 'douyin search' as an expected empty outcome in scripts."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  rows = await douyinSearch(keyword);\n} catch (e) {\n  if (e.name === 'EmptyResultError' && e.scope === 'douyin search') return [];\n  throw e;\n}","preventionTips":["Verify selectors still match the live Douyin markup when empties spike.","Test with a high-traffic keyword to distinguish real empties from selector rot.","Account for region/locale differences that can hide results."],"tags":["empty-results","douyin","selectors"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}