jackwener/OpenCLI · error · CommandExecutionError
Douyin search parser found result cards without stable video
Error message
Douyin search parser found result cards without stable video url or description
What it means
CommandExecutionError thrown when projectSearchCards reports invalidCount > 0: Douyin rendered result cards, but at least one lacked a stable video URL or description, so the adapter refuses to emit partially-garbage rows. This protects downstream consumers of the tiktok-compatible row schema.
Source
Thrown at clis/douyin/search.js:301
'www.douyin.com',
'Douyin search results are blocked behind a login wall — log in at https://www.douyin.com in Chrome first.',
);
}
if (result.state === 'empty') {
throw new EmptyResultError('douyin search', `No Douyin videos matched "${keyword}".`);
}
if (result.state === 'timeout') {
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.');
}
if (!Array.isArray(result.cards)) {
throw new CommandExecutionError('Douyin search: evaluator returned malformed cards payload');
}
if (result.cards.length === 0) {
throw new EmptyResultError('douyin search', `No Douyin videos matched "${keyword}".`);
}
const projected = projectSearchCards(result.cards, limit);
if (projected.invalidCount > 0) {
throw new CommandExecutionError('Douyin search parser found result cards without stable video url or description');
}
if (projected.rows.length === 0) {
throw new EmptyResultError('douyin search', `No Douyin videos matched "${keyword}".`);
}
return projected.rows;
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the failing card HTML in the bound browser and update projectSearchCards' extraction hooks.
- Retry — if only ad cards appeared this run, a rerun may return all-valid cards.
- Relax the all-or-nothing policy locally by filtering invalid rows instead of throwing, if partial results are acceptable.
Example fix
// before
if (projected.invalidCount > 0) {
throw new CommandExecutionError('Douyin search parser found result cards without stable video url or description');
}
// after (lenient variant)
if (projected.rows.length === 0) {
throw new CommandExecutionError('Douyin search parser found no valid result cards');
} Defensive patterns
Strategy: validation
Validate before calling
function cardLooksValid(card) {
return typeof card?.url === 'string' && /\/video\/\d+/.test(card.url) && typeof card?.desc === 'string' && card.desc.length > 0;
} Type guard
function isValidSearchRow(row) {
return typeof row?.url === 'string' && row.url.startsWith('https://www.douyin.com/video/')
&& typeof row?.desc === 'string';
} Try / catch
try {
rows = await douyinSearch(keyword);
} catch (e) {
if (/without stable video url or description/.test(e.message)) {
console.error('Douyin markup drift or ad cards; inspect page HTML and update extractors');
}
throw e;
} Prevention
- Re-verify extraction hooks after known Douyin front-end deploys.
- Sample rendered card HTML periodically in a smoke test.
- Prefer stable hooks (data-e2e, /video/ links) over obfuscated classnames.
When it happens
Trigger: Douyin markup change breaks the a[href*='/video/'] hook or the leaf-text shape heuristics; promoted/ad cards in the list have different structure; mixed content (live/hot cards) interleaved with video cards.
Common situations: After a Douyin front-end deploy; when search results include ads or recommended non-video cards; locale variations altering text shapes (万/亿 suffixes).
Related errors
- douyin search
- Failed to parse 12306 station_name.js: source string not fou
- Failed to parse 12306 station_name.js: no station records fo
- archive search returned malformed JSON: ${error?.message ||
- archive wayback returned malformed JSON: ${error?.message ||
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a5a2e2d0c674c939.
Report an issue: GitHub.