jackwener/OpenCLI · error · CommandExecutionError
Ctrip train page did not render train cards (state=${String(
Error message
Ctrip train page did not render train cards (state=${String(waitResult)}) What it means
Thrown as CommandExecutionError when the Ctrip train page loads but never reaches the expected 'content' state: the in-page wait script returned something other than 'content' or 'captcha'. The DOM never rendered train cards, so scraping cannot proceed. This indicates a page-structure or load problem rather than bad input.
Source
Thrown at clis/ctrip/train.js:60
'url',
],
func: async (page, kwargs) => {
const fromName = parsePlaceName('from', kwargs.from);
const toName = parsePlaceName('to', kwargs.to);
if (fromName === toName) {
throw new ArgumentError(`--from and --to must differ (got ${fromName})`);
}
const date = parseIsoDate('date', kwargs.date);
const limit = parseListLimit(kwargs.limit);
const searchUrl = buildTrainListUrl(fromName, toName, date);
await page.goto(searchUrl);
const waitResult = await page.evaluate(WAIT_FOR_TRAINS_JS);
if (waitResult === 'captcha') {
throw new AuthRequiredError('trains.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
}
if (waitResult !== 'content') {
throw new CommandExecutionError(`Ctrip train page did not render train cards (state=${String(waitResult)})`);
}
const renderedCardCount = await page.evaluate(buildScrollUntilJs('.card-white.list-item', limit));
const raw = await page.evaluate(buildTrainExtractJs());
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Ctrip train DOM extraction returned malformed rows');
}
if (raw.length === 0) {
if (Number(renderedCardCount) > 0) {
throw new CommandExecutionError('Ctrip train cards rendered but parser did not find required train anchors');
}
throw new EmptyResultError('ctrip train', `No trains for ${fromName} to ${toName} on ${date}`);
}
return raw.slice(0, limit).map((r, i) => ({
rank: i + 1,
trainNo: r.trainNo,
departureTime: r.departureTime,
departureStation: r.departureStation,
arrivalTime: r.arrivalTime,View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the query once — transient slowness often causes this.
- Check WAIT_FOR_TRAINS_JS selectors against current trains.ctrip.com markup and update if Ctrip changed the page.
- Increase the wait timeout if on a slow connection.
- Run in a visible (non-headless) browser to see what the page actually shows.
Example fix
// before
const raw = await scrapeTrains({ from, to, date });
// after
let raw;
try { raw = await scrapeTrains({ from, to, date }); }
catch (e) { if (e instanceof CommandExecutionError) raw = await retry(scrapeTrains, { from, to, date }); else throw e; } Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
try { return await runTrainList(opts); } catch (e) { if (e instanceof CommandExecutionError && /did not render/.test(e.message)) { await sleep(5000); return retryOnce(opts); } throw e; } Prevention
- Retry transient render failures once with backoff
- Run on a stable/fast network
- Pin/patch WAIT_FOR_TRAINS_JS selectors when Ctrip updates markup
- Debug headlessly-invisible pages with headful runs
When it happens
Trigger: WAIT_FOR_TRAINS_JS times out or reports states like 'timeout'/'error' after page.goto(searchUrl); Ctrip markup changed, slow network, or the page served an unexpected interstitial.
Common situations: Ctrip A/B-changing their train list DOM; slow proxy or throttled network causing render timeout; regional redirects to a different page layout; JS errors on the page blocking rendering.
Related errors
- Ctrip place page did not render attraction links for city id
- Ctrip bus page did not render schedule rows (state=${String(
- Ctrip cruise page did not render (state=${String(indexWait)}
- Ctrip round-trip flight page did not render flight cards (st
- Trip.com flight page did not render flight cards (state=${St
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9e86748f6c78b38a.
Report an issue: GitHub.