jackwener/OpenCLI · error · CommandExecutionError

Trip.com transfer DOM extraction returned malformed rows

Error message

Trip.com transfer DOM extraction returned malformed rows

What it means

CommandExecutionError thrown when the transfer page loaded and passed all checks, but page.evaluate(buildTransferExtractJs()) returned a non-array. The rendered page's DOM no longer matches the extraction script's expectations, so it produced null or an object instead of a rows array.

Source

Thrown at clis/trip/transfer.js:67

        const listUrl = buildTransferListUrl(city, airport);
        await page.goto(listUrl);
        const waitResult = await page.evaluate(WAIT_FOR_TRANSFERS_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 transfer', `No airport transfers for ${city} (${airport})`);
        }
        if (waitResult !== 'content') {
            throw new CommandExecutionError(`Trip.com transfer listing did not render (state=${String(waitResult)}); check the city and airport code`);
        }
        const landedPath = await page.evaluate('location.pathname');
        if (!/\/airport-transfers\/[^/]+\/airport-[^/]+/i.test(String(landedPath))) {
            throw new CommandExecutionError(`Trip.com bounced ${city} / ${airport} to the transfer landing; check the city name matches the airport IATA code`);
        }
        const raw = await page.evaluate(buildTransferExtractJs());
        if (!Array.isArray(raw)) {
            throw new CommandExecutionError('Trip.com transfer DOM extraction returned malformed rows');
        }
        if (raw.length === 0) {
            throw new CommandExecutionError('Trip.com transfer cards rendered but parser did not find required price anchors');
        }
        return raw.slice(0, limit).map((r, i) => ({
            rank: i + 1,
            type: r.type,
            passengers: r.passengers,
            luggage: r.luggage,
            price: r.price,
            currency: r.currency,
            url: listUrl,
        }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update buildTransferExtractJs() to match current transfer card DOM
  2. Log the raw evaluate output to diagnose the actual returned shape
  3. Disable/bypass A/B variants so the stable layout renders
  4. Retry in case a partial render produced a degenerate DOM

Example fix

// before
const raw = await page.evaluate(buildTransferExtractJs());
if (!Array.isArray(raw)) throw new CommandExecutionError('malformed rows');
// after
const raw = await page.evaluate(buildTransferExtractJs());
if (!Array.isArray(raw)) {
  await page.screenshot({ path: 'transfer-debug.png' });
  throw new CommandExecutionError('malformed rows, screenshot saved');
}
Defensive patterns

Strategy: type-guard

Validate before calling

// guard the raw result shape
const raw = await page.evaluate(buildTransferExtractJs());
if (raw === null) throw new Error('extractor matched nothing — DOM drift');

Type guard

function isTransferRows(v) {
  return Array.isArray(v) && v.every(r => r && typeof r.type === 'string' && 'passengers' in r);
}

Try / catch

try {
  const rows = await getTransfers(args);
} catch (e) {
  if (e.message.includes('malformed rows')) {
    await page.screenshot({ path: 'transfer-dom-drift.png' }).catch(() => {});
  }
  throw e;
}

Prevention

When it happens

Trigger: Trip.com redesign of transfer card markup so the extractor's selectors match nothing and it returns null; a page script clobbering the extractor's globals; serialization failure of the evaluate payload.

Common situations: Trip.com A/B tests or frontend deploys changing transfer card structure; extractor pinned to old class names; headless browser rendering a fallback/legacy layout.

Understand the failure class

Related errors


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