jackwener/OpenCLI · error · CommandExecutionError

Trip.com tour search returned malformed data

Error message

Trip.com tour search returned malformed data

What it means

This CommandExecutionError is thrown when the in-page tour-search script returns null or a non-object, meaning the browser automation could not extract the expected structured result from the Trip.com tours page. It indicates the page did not run/complete the embedded extraction JS as designed — a page-level failure, not an empty search.

Source

Thrown at clis/trip/tour.js:56

        { name: 'limit', type: 'int', default: 20, help: 'Number of tours (1-50)' },
    ],
    columns: [
        'rank',
        'name', 'type',
        'rating', 'reviews',
        'price', 'currency',
        'url',
    ],
    func: async (page, kwargs) => {
        const query = parseKeyword('query', kwargs.query);
        const tourType = parseTourType(kwargs.type);
        const limit = parseListLimit(kwargs.limit);

        const searchUrl = buildTourSearchUrl(query, tourType);
        await page.goto(searchUrl);
        const result = await page.evaluate(buildTourSearchJs(query));
        if (!result || typeof result !== 'object') {
            throw new CommandExecutionError('Trip.com tour search returned malformed data');
        }
        if (result.status === 'captcha') {
            throw new AuthRequiredError('trip.com', 'Trip.com is asking for a verification; complete it in your browser session and retry');
        }
        if (result.status === 'empty') {
            throw new EmptyResultError('trip tour', `No ${kwargs.type || 'private'} tours for "${query}"`);
        }
        if (result.status !== 'content') {
            throw new CommandExecutionError(`Trip.com tour search did not return results (state=${String(result.status)})`);
        }
        // Products captured but none carry a name is drift (schema moved), not an empty search;
        // a genuine no-match resolves as status 'empty' above off the page's "0 routes found".
        const rows = Array.isArray(result.rows) ? result.rows.filter((r) => r.name) : [];
        if (rows.length === 0) {
            throw new CommandExecutionError('Trip.com tour search captured products but none carried a name (the product markup may have changed)');
        }
        return rows.slice(0, limit).map((r, i) => ({
            rank: i + 1,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the search — transient page-load failures often resolve on a second attempt.
  2. Increase any page load/timeout budgets so the tours page fully renders before evaluation.
  3. Manually open the built searchUrl in a browser to see what the page actually shows (redirect, consent wall, error page).
  4. Update buildTourSearchJs if the site changed structure or entry behavior.

Example fix

// before
const result = await page.goto(searchUrl); // no wait
const r = await page.evaluate(buildTourSearchJs(query));
// after
await page.goto(searchUrl, { waitUntil: 'networkidle' });
const r = await page.evaluate(buildTourSearchJs(query));
Defensive patterns

Strategy: retry

Validate before calling

// preflight: ensure the browser session is alive and the URL is reachable
const resp = await fetch(searchUrl, { method: 'HEAD' }).catch(() => null);
if (!resp || !resp.ok) throw new Error('Trip.com tours page unreachable before automation');

Type guard

function isSearchResult(r) { return r !== null && typeof r === 'object' && !Array.isArray(r); }

Try / catch

try {
  const rows = await tourSearch(query, type);
} catch (e) {
  if (/malformed data/.test(e.message)) {
    await sleep(2000);
    return tourSearch(query, type); // single retry
  }
  throw e;
}

Prevention

When it happens

Trigger: page.evaluate(buildTourSearchJs(query)) returning undefined/null or a primitive — e.g. the extraction script threw inside the page, the page navigated away/redirected, or the DOM the script expects never rendered.

Common situations: Slow network so the page never reached the expected state; Trip.com redirecting to a different regional domain or consent page; the extraction script's entry-point selector disappearing after a site update.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/4062f15af525c840. Report an issue: GitHub.