jackwener/OpenCLI · error · CommandExecutionError
Douyin search extraction failed: ${error instanceof Error ?
Error message
Douyin search extraction failed: ${error instanceof Error ? error.message : String(error)} What it means
The search command injects WAIT_AND_EXTRACT_JS into the Douyin search page and unwraps the result. Any failure inside the page evaluator — timeout waiting for results, login wall detection throwing, script errors — is caught and rethrown as this CommandExecutionError with the underlying message, so the browser-side cause is preserved.
Source
Thrown at clis/douyin/search.js:276
domain: 'www.douyin.com',
strategy: Strategy.COOKIE,
args: [
{ name: 'query', required: true, positional: true, help: '搜索关键词' },
{ name: 'limit', type: 'int', default: 10, help: `结果数量 (1-${MAX_SEARCH_LIMIT})` },
],
columns: ['rank', 'desc', 'author', 'url', 'plays', 'likes', 'comments', 'shares'],
func: async (page, kwargs) => {
const limit = parseSearchLimit(kwargs.limit);
const keyword = String(kwargs.query ?? '').trim();
if (!keyword) {
throw new ArgumentError('douyin search 需要 <query> 关键词');
}
await page.goto(`https://www.douyin.com/search/${encodeURIComponent(keyword)}?type=video`);
let result;
try {
result = unwrapEvaluateResult(await page.evaluate(WAIT_AND_EXTRACT_JS(RENDER_TIMEOUT_MS)));
} catch (error) {
throw new CommandExecutionError(`Douyin search extraction failed: ${error instanceof Error ? error.message : String(error)}`);
}
if (!result || typeof result !== 'object') {
throw new CommandExecutionError('Douyin search: unexpected evaluator payload shape');
}
if (result.state === 'login_wall') {
throw new AuthRequiredError(
'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');View on GitHub (pinned to 49907e53dc)
Solutions
- Read the wrapped inner message to identify timeout vs selector vs auth cause
- Retry with a stable/faster network or increase RENDER_TIMEOUT_MS if timeouts dominate
- Log in the automation browser if results are behind an anonymous gate (login_wall)
- Update WAIT_AND_EXTRACT_JS selectors after a Douyin page-structure change
Example fix
// before
const res = await douyin.search({ query: 'cats', limit: 10 }); // anonymous browser
// after (pre-authenticated context)
const res = await douyin.search({ query: 'cats', limit: 10 }); // with logged-in session/retry
// or wrap:
try { ... } catch (e) { if (/timeout/i.test(e.message)) await sleep(5000); /* retry once */ } Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: ensure session is usable and network is up before scraping
const ok = await fetch('https://www.douyin.com', { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!ok) throw new Error('douyin.com unreachable; fix network before search'); Type guard
function isSearchResult(v) {
return v !== null && typeof v === 'object' && Array.isArray(v.videos);
} Try / catch
try {
const res = await douyin.search({ query, limit });
} catch (e) {
if (e instanceof CommandExecutionError && /extraction failed/.test(e.message)) {
if (/timeout/i.test(e.message)) { await sleep(5000); /* retry once */ }
else if (/login/i.test(e.message)) { /* refresh session */ }
else console.error('Selectors may be stale; update extraction script:', e.message);
} else throw e;
} Prevention
- Use a logged-in browser profile to avoid anonymous gating/login walls
- Retry timeouts once with backoff before failing
- Pin/selectors-test against Douyin's search DOM; update after redesigns
- Run from a network path with low latency to douyin.com
When it happens
Trigger: page.evaluate of WAIT_AND_EXTRACT_JS throws or the returned payload fails unwrapEvaluateResult — render timeout after RENDER_TIMEOUT_MS (15s), DOM selectors changed on Douyin's search page, in-page JS exception, or navigation interrupted.
Common situations: Douyin front-end redesign breaking extraction selectors; slow network or heavy page causing the 15s render timeout; anonymous gating/login wall; rate limiting serving an interstitial page without expected nodes.
Related errors
- Timed out waiting for network idle after ${waitSeconds}s
- TimeoutError
- IMDb search results did not finish loading
- Timed out waiting for selector "${kwargs['wait-for']}" in ma
- weixin search failed while loading Sogou results
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a2d3130191a7c50b.
Report an issue: GitHub.