jackwener/OpenCLI · error · CommandExecutionError
Trip.com attraction DOM extraction returned malformed rows
Error message
Trip.com attraction DOM extraction returned malformed rows
What it means
This CommandExecutionError is thrown when page.evaluate(buildAttractionExtractJs()) returns something other than an array — i.e. the DOM extraction script produced malformed output instead of a list of attraction rows. It indicates the extraction script and the live page DOM are out of sync, not that results are empty (that would be error 3905 or 3902).
Source
Thrown at clis/trip/attraction.js:58
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
- Retry once — a transient render race can produce a malformed extraction; persistent failures mean a DOM change.
- Open the things-to-do URL in a normal browser and compare card markup against the selectors used by buildAttractionExtractJs in clis/trip/utils.js.
- Update the extraction script's selectors to match the new Trip.com card structure (detail-link anchors).
- Report/patch the library if Trip.com changed its layout; pin to an older working version meanwhile.
Example fix
// before: assuming array always returned
const raw = await page.evaluate(buildAttractionExtractJs());
const rows = raw.slice(0, limit);
// after: caller-side guard
const raw = await page.evaluate(buildAttractionExtractJs());
if (!Array.isArray(raw)) throw new Error('Trip.com extraction returned non-array; selectors likely stale');
const rows = raw.slice(0, limit); Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
function isExtractionRows(value) {
return Array.isArray(value) && value.every(
(r) => r && typeof r === 'object' && typeof r.url === 'string'
);
} Try / catch
try {
return await runCli(['trip', 'attraction', query]);
} catch (e) {
if (/malformed rows/.test(e.message)) {
// selectors stale vs live DOM — surface actionable error, optionally retry once
throw new Error('Trip.com attraction extraction is stale; update buildAttractionExtractJs selectors');
}
throw e;
} Prevention
- Guard any in-page evaluate result with Array.isArray before consuming it.
- Watch Trip.com things-to-do markup for redesigns; pin and test selectors regularly.
- Distinguish 'malformed rows' (script/DOM mismatch) from 'parser found 0 anchors' (empty parse).
- One retry is reasonable, but persistent malformed output needs a selector patch, not retries.
When it happens
Trigger: Running `trip attraction` when the in-page extraction JS returns null/undefined/an object instead of an array — typically because the things-to-do page markup changed so the script's row-collection logic fails, or evaluate was interrupted.
Common situations: Trip.com deployed a redesign of the things-to-do cards so buildAttractionExtractJs no longer collects rows; a partially rendered/interactive-error page where expected DOM containers are absent; a Trip.com error page that still passes the 'content' wait check but has a different structure.
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
- Trip.com car DOM extraction returned malformed rows
- Trip.com transfer cards rendered but parser did not find req
- Not a git repository
- Trip.com attraction cards rendered but parser did not find r
- Trip.com car cards rendered but parser did not find required
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/665c5c1954803ad0.
Report an issue: GitHub.