jackwener/OpenCLI · error · CommandExecutionError
Ctrip train DOM extraction returned malformed rows
Error message
Ctrip train DOM extraction returned malformed rows
What it means
Thrown as CommandExecutionError when buildTrainExtractJs's in-page extraction returns a non-array value instead of a list of train rows. The library treats any non-array extraction result as malformed DOM output and refuses to continue, protecting downstream mapping code from undefined fields.
Source
Thrown at clis/ctrip/train.js:65
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,
arrivalStation: r.arrivalStation,
duration: r.duration,
fromPrice: r.fromPrice,
seats: Array.isArray(r.seats) && r.seats.length ? r.seats.join(' / ') : null,
url: searchUrl,View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the query; if persistent, inspect the live page DOM against the selectors in buildTrainExtractJs.
- Update extraction selectors in buildTrainExtractJs to match current Ctrip markup.
- Log the raw evaluate result to see what shape is actually returned.
Example fix
// before
const raw = await page.evaluate(buildTrainExtractJs());
if (!Array.isArray(raw)) throw new CommandExecutionError('malformed rows');
// after
const raw = await page.evaluate(buildTrainExtractJs());
const rows = Array.isArray(raw) ? raw : (raw && Array.isArray(raw.trains) ? raw.trains : null);
if (!rows) throw new CommandExecutionError('malformed rows'); Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
const isTrainRows = (v) => Array.isArray(v) && v.every(r => r && typeof r.trainNo === 'string');
Try / catch
try { return await runTrainList(opts); } catch (e) { if (e instanceof CommandExecutionError && /malformed rows/.test(e.message)) { return fallbackScraper(opts); } throw e; } Prevention
- Keep buildTrainExtractJs selectors in sync with Ctrip DOM
- Log raw evaluate output when debugging
- Wrap evaluate calls to normalize NodeList-like returns to arrays
When it happens
Trigger: page.evaluate(buildTrainExtractJs()) returning undefined/null/object because the page context errored, the extraction script's querySelectorAll returned nothing in an unexpected shape, or evaluate serialization failed.
Common situations: Ctrip changing container class names so the extractor's root lookup fails; page.evaluate returning a NodeList-like that isn't a plain array; a prior script error leaving the extractor's return value undefined.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Ctrip train cards rendered but parser did not find required
- Ctrip round-trip flight DOM extraction returned malformed ro
- Ctrip round-trip flight cards rendered but parser did not fi
- Ctrip round-trip flight rows were missing required airline/f
- Ctrip package DOM extraction returned malformed rows
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8b386ac94826ad17.
Report an issue: GitHub.