jackwener/OpenCLI · error · CommandExecutionError
Trip.com things-to-do page did not render product cards (sta
Error message
Trip.com things-to-do page did not render product cards (state=${String(waitResult)}) What it means
The `trip attraction` command throws this CommandExecutionError when the in-page wait script neither confirmed content ('content'), emptiness ('empty'), nor a challenge ('captcha') — the page ended in some other state, so product cards never rendered. The state value is embedded in the message for debugging. It usually means Trip.com's SPA never finished hydrating or changed its loading markup.
Source
Thrown at clis/trip/attraction.js:54
'rating', 'reviews', 'booked',
'price', 'currency',
'url',
],
func: async (page, kwargs) => {
const query = parseKeyword('query', kwargs.query);
const limit = parseListLimit(kwargs.limit);
const searchUrl = buildAttractionSearchUrl(query);
await page.goto(searchUrl);
const waitResult = await page.evaluate(WAIT_FOR_ATTRACTIONS_JS);
if (waitResult === 'captcha') {
throw new AuthRequiredError('trip.com', 'Trip.com is asking for a verification; complete it in your browser session and retry');
}
if (waitResult === 'empty') {
throw new EmptyResultError('trip attraction', `No attractions for "${query}"`);
}
if (waitResult !== 'content') {
throw new CommandExecutionError(`Trip.com things-to-do page did not render product cards (state=${String(waitResult)})`);
}
const raw = await page.evaluate(buildAttractionExtractJs());
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Trip.com attraction DOM extraction returned malformed rows');
}
if (raw.length === 0) {
throw new CommandExecutionError('Trip.com attraction cards rendered but parser did not find required detail-link anchors');
}
return raw.slice(0, limit).map((r, i) => ({
rank: i + 1,
name: r.name,
rating: r.rating,
reviews: r.reviews,
booked: r.booked,
price: r.price,
currency: 'USD',
url: r.url,
}));View on GitHub (pinned to 49907e53dc)
Solutions
- Read the `state=` value in the message: if it indicates a timeout, simply retry — slow renders are often transient.
- Increase browser navigation/wait timeouts in the shared page setup and rerun.
- Check Trip.com in a normal browser to see whether the things-to-do page layout changed; if so the library's wait script needs updating.
- Improve network conditions or run closer to Trip.com's region to speed up client-side hydration.
Example fix
// before
await runCli(['trip', 'attraction', query]);
// after: retry once on render-state failure
try {
await runCli(['trip', 'attraction', query]);
} catch (e) {
if (e.name === 'CommandExecutionError' && /did not render product cards/.test(e.message)) {
await sleep(3000);
return runCli(['trip', 'attraction', query]);
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
async function withRetry(fn, attempts = 2) {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (e) {
const transient = /did not render product cards \(state=/.test(e.message);
if (transient && i < attempts - 1) { await sleep(3000); continue; }
throw e;
}
}
} Prevention
- Run on a stable, fast network so SPA hydration finishes within the wait window.
- Keep the library updated — Trip.com layout changes can invalidate wait selectors.
- Retry with backoff on render-state failures rather than failing immediately.
- Log the `state=` value from the message to distinguish timeouts from layout changes.
When it happens
Trigger: page.evaluate(WAIT_FOR_ATTRACTIONS_JS) returns any value other than 'content'/'empty'/'captcha' — e.g. a timeout sentinel or null — after page.goto on the attraction search URL, such as slow client-side rendering exceeding the wait script's internal deadline.
Common situations: Slow network / throttled connection where hydration outlasts the wait window; Trip.com A/B tests changing the things-to-do page structure so the wait selector never matches; transient server errors returning a stub page; heavy CPU contention on the machine running the headless browser.
Related errors
- Trip.com car listing did not render (state=${String(waitResu
- Trip.com is asking for a verification; complete it in your b
- No attractions for "${query}"
- Trip.com attraction DOM extraction returned malformed rows
- Trip.com is asking for a verification; complete it in your b
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ed7c21e3224fd14d.
Report an issue: GitHub.