jackwener/OpenCLI · error · CommandExecutionError
Ctrip cruise port page did not render (state=${String(portWa
Error message
Ctrip cruise port page did not render (state=${String(portWait)}) What it means
CommandExecutionError thrown when the port's cruise.ctrip.com page neither rendered content nor showed the known empty state — WAIT_FOR_CRUISE_JS returned some other state (timeout, unknown selector state, navigation hiccup). The library cannot classify the page, so it fails with the raw wait state embedded in the message for diagnosis. It indicates a page-load/render problem rather than a data or auth problem.
Source
Thrown at clis/ctrip/cruise.js:74
}
const portCode = await page.evaluate(buildCruisePortLookupJs(port));
if (!portCode) {
throw new EmptyResultError('ctrip cruise', `No cruise departure port matching "${port}" (try a listed sea-cruise port like 上海 / 威尼斯 / 罗马)`);
}
let searchUrl = indexUrl;
if (portCode !== PORT_INDEX_CODE) {
searchUrl = buildCruiseSearchUrl(portCode);
await page.goto(searchUrl);
const portWait = await page.evaluate(WAIT_FOR_CRUISE_JS);
if (portWait === 'captcha') {
throw new AuthRequiredError('cruise.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
}
if (portWait === 'empty') {
throw new EmptyResultError('ctrip cruise', `No cruises currently departing "${port}"`);
}
if (portWait !== 'content') {
throw new CommandExecutionError(`Ctrip cruise port page did not render (state=${String(portWait)})`);
}
}
const raw = await page.evaluate(buildCruiseExtractJs());
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Ctrip cruise DOM extraction returned malformed rows');
}
if (raw.length === 0) {
throw new CommandExecutionError('Ctrip cruise cards rendered but parser did not find required itinerary anchors');
}
return raw.slice(0, limit).map((r, i) => ({
rank: i + 1,
title: r.title,
star: r.star,
boarding: r.boarding,
sailingDate: r.sailingDate,
tags: r.tags,
price: r.price,View on GitHub (pinned to 49907e53dc)
Solutions
- Read the state value in the message and rerun once — transient loads often succeed on retry
- Increase the browser wait/navigation timeout used by the CLI before rerunning
- Open buildCruiseSearchUrl(portCode) in a real browser to see what actually renders (captcha, error page, new layout)
- Update the CLI (or WAIT_FOR_CRUISE_JS in clis/ctrip/utils.js) if Ctrip changed its page structure
Example fix
// before: single fragile attempt
await run(['ctrip', 'cruise', '威尼斯']);
// after: one retry on render failure
try {
await run(['ctrip', 'cruise', '威尼斯']);
} catch (e) {
if (e.name === 'CommandExecutionError' && /did not render/.test(e.message)) {
await sleep(3000);
await run(['ctrip', 'cruise', '威尼斯']);
} else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: probe network reachability and page load latency before running the command
const t0 = Date.now();
await fetch('https://cruise.ctrip.com/', { method: 'HEAD' });
if (Date.now() - t0 > 5000) console.warn('Slow route to Ctrip; raise the CLI wait timeout'); Type guard
function isRenderFailure(e) {
return e instanceof Error && e.name === 'CommandExecutionError' && /did not render/.test(e.message);
} Try / catch
try {
return await run(['ctrip', 'cruise', port]);
} catch (e) {
if (isRenderFailure(e)) {
await sleep(3000);
return run(['ctrip', 'cruise', port]); // one retry with backoff
}
throw e;
} Prevention
- Run with a stable, low-latency network connection to Ctrip domains
- Raise browser navigation/wait timeouts in slow or proxied environments
- Keep the CLI updated so WAIT_FOR_CRUISE_JS tracks current Ctrip markup
- Check the state= value in the message — consistent unknown states mean a markup change, not flakiness
When it happens
Trigger: Calling `ctrip cruise <port>` where after page.goto on the port results URL the in-page probe times out or returns an unrecognized state (network slowness, SPA hydration failure, unexpected page markup, redirect to an error page).
Common situations: Slow or proxied network causing the wait timeout to expire before the SPA hydrates; Ctrip A/B-deploying new markup so the probe's known selectors vanish; transient 5xx or interstitial pages breaking navigation; headless environment where some resources never load.
Related errors
- Ctrip ferry page did not render sailing rows (state=${String
- Ctrip round-trip flight page did not render flight cards (st
- Midjourney image upload input did not become active
- NO_DIALOG
- Unexpected 12306 probe: ${JSON.stringify(probe)}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9fd8b2fa71d59ea6.
Report an issue: GitHub.