jackwener/OpenCLI · error · EmptyResultError

ctrip hotel-search

Error message

ctrip hotel-search

What it means

CommandExecutionError thrown when the SSR hotel list extracted from the Ctrip search page via EXTRACT_HOTELS_JS is not an array. The library expects page.evaluate to return an array of raw hotel entries; anything else (null, object, string) means the page structure changed or the page did not render the expected SSR data. It is thrown to fail fast instead of crashing later in mapHotelRow.

Source

Thrown at clis/ctrip/hotel-search.js:111

        const checkout = parseIsoDate('checkout', kwargs.checkout);
        assertCheckinBeforeCheckout(checkin, checkout);
        const limit = parseHotelLimit(kwargs.limit);

        const url = `https://hotels.ctrip.com/hotels/list?city=${cityId}&checkin=${checkin}&checkout=${checkout}`;
        await page.goto(url);
        const waitResult = await page.evaluate(WAIT_FOR_SSR_JS);
        if (waitResult === 'captcha') {
            throw new AuthRequiredError('hotels.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
        }
        if (waitResult !== 'content') {
            throw new CommandExecutionError(`Ctrip hotel-search page did not expose SSR hotel list (state=${String(waitResult)})`);
        }
        const raw = await page.evaluate(EXTRACT_HOTELS_JS);
        if (!Array.isArray(raw)) {
            throw new CommandExecutionError('Ctrip hotel-search returned malformed SSR hotel list');
        }
        if (raw.length === 0) {
            throw new EmptyResultError('ctrip hotel-search', `No hotels for city=${cityId} on ${checkin} → ${checkout}`);
        }
        const rows = raw
            .map((entry, i) => mapHotelRow(entry, i))
            .filter((row) => row.hotelId && row.name)
            .slice(0, limit);
        if (rows.length === 0) {
            throw new CommandExecutionError('Ctrip hotel-search SSR rows were missing required hotelId/name anchors');
        }
        return rows;
    },
});

export const __test__ = { parseHotelLimit, assertCheckinBeforeCheckout, WAIT_FOR_SSR_JS, EXTRACT_HOTELS_JS };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the search; transient interstitials often resolve on retry
  2. Log the raw page.evaluate output and update EXTRACT_HOTELS_JS to the new SSR data shape
  3. Verify the page is not showing a captcha and refresh your browser session/cookies
  4. Update the CLI to the latest version with fixed selectors

Example fix

// before
const raw = await page.evaluate(EXTRACT_HOTELS_JS);
if (!Array.isArray(raw)) {
  throw new CommandExecutionError('Ctrip hotel-search returned malformed SSR hotel list');
}
// after
let raw = await page.evaluate(EXTRACT_HOTELS_JS);
if (!Array.isArray(raw)) {
  raw = await page.evaluate(EXTRACT_HOTELS_JS_FALLBACK_V2); // alternate selector
  if (!Array.isArray(raw)) throw new CommandExecutionError('...');
}
Defensive patterns

Strategy: try-catch

Validate before calling

const raw = await page.evaluate(EXTRACT_HOTELS_JS);
if (!Array.isArray(raw)) throw new Error('SSR hotel list is not an array — page shape changed or captcha shown');

Type guard

const isHotelRowArray = (v) => Array.isArray(v) && v.every((e) => e && typeof e === 'object');

Try / catch

try {
  const rows = await ctrip.hotelSearch({ cityId, checkin, checkout });
} catch (e) {
  if (e instanceof CommandExecutionError && /malformed SSR hotel list/.test(e.message)) {
    // retry once, then surface as upstream-structure failure
  } else throw e;
}

Prevention

When it happens

Trigger: page.evaluate(EXTRACT_HOTELS_JS) returns a non-array value after running the Ctrip hotel-search page: Ctrip redesigned its SSR data payload, a captcha/interstitial replaced the hotel list, or the extract script matched no window.__initialState-like object and returned null/undefined.

Common situations: Ctrip front-end update changing the SSR state key; scraping from a region that gets bot-challenged; running an outdated CLI against a new Ctrip page version; transient network issues producing a partial HTML shell.

Related errors


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