jackwener/OpenCLI · error · CommandExecutionError

Ctrip flight requires browser response interception

Error message

Ctrip flight requires browser response interception

What it means

This CommandExecutionError fires when the browser page object passed to the `ctrip flight` command does not support the network-response interception the command depends on: page.startNetworkCapture and page.readNetworkCapture must both be functions, and startNetworkCapture('/international/search/api/search/batchSearch') must return a truthy value. The command's strategy is Strategy.INTERCEPT — row data comes exclusively from the captured batchSearch XHR, so without interception it cannot produce results.

Source

Thrown at clis/ctrip/flight.js:183

        'price', 'currency', 'cabin',
        'url',
    ],
    func: async (page, kwargs) => {
        const fromCode = parseIataCode('from', kwargs.from);
        const toCode = parseIataCode('to', kwargs.to);
        if (fromCode === toCode) {
            throw new ArgumentError(`--from and --to must differ (got ${fromCode})`);
        }
        const date = parseIsoDate('date', kwargs.date);
        const limit = parseFlightLimit(kwargs.limit);

        const searchUrl =
            `https://flights.ctrip.com/online/list/oneway-${fromCode.toLowerCase()}-${toCode.toLowerCase()}` +
            `?depdate=${date}&cabin=Y_S_C_F&adult=1&child=0&infant=0`;
        if (typeof page?.startNetworkCapture !== 'function' ||
            typeof page?.readNetworkCapture !== 'function' ||
            !await page.startNetworkCapture(CAPTURE_PATTERN)) {
            throw new CommandExecutionError('Ctrip flight requires browser response interception');
        }
        await page.readNetworkCapture();
        await page.goto(searchUrl);
        // The initial document can finish before the large batchSearch body.
        // The first rendered card is only a readiness signal; row data still
        // comes exclusively from the structured response below.
        const readiness = await page.evaluate(WAIT_FOR_BATCH_CAPTURE_JS);
        if (readiness === 'captcha') {
            throw new AuthRequiredError('flights.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
        }
        const itineraries = parseBatchSearchCaptures(await page.readNetworkCapture());
        if (!itineraries) {
            throw new TimeoutError('Ctrip flight API capture', CAPTURE_TIMEOUT_SECONDS, 'No batchSearch response was observed after opening the results page.');
        }
        if (itineraries.length === 0) {
            throw new EmptyResultError('ctrip flight', `No flights for ${fromCode}→${toCode} on ${date}`);
        }
        const rows = itineraries

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Run the command through the standard opencli browser (browser: true, Strategy.INTERCEPT) so page gets startNetworkCapture/readNetworkCapture.
  2. Upgrade @jackwener/opencli to a version whose browser exposes the network capture APIs.
  3. If testing, stub page.startNetworkCapture (returning true) and page.readNetworkCapture in your mock page object.
  4. Check that the CDP session can enable network interception (no restricted browser/extension blocking Fetch/Network domains).

Example fix

// before: plain puppeteer page handed to the command
const page = await browser.newPage();
await runCommand('ctrip flight', { page });

// after: use the opencli-managed page with capture support
const page = await opencliBrowser.newPage({ intercept: true });
await runCommand('ctrip flight', { page });
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify capture support before invoking the command
function supportsInterception(page) {
  return typeof page?.startNetworkCapture === 'function' &&
         typeof page?.readNetworkCapture === 'function';
}
if (!supportsInterception(page)) throw new Error('page lacks network capture APIs');

Type guard

function isInterceptCapablePage(page) {
  return page != null &&
    typeof page.startNetworkCapture === 'function' &&
    typeof page.readNetworkCapture === 'function' &&
    typeof page.goto === 'function' &&
    typeof page.evaluate === 'function';
}

Try / catch

try {
  const rows = await ctripFlight({ from, to, date });
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('requires browser response interception')) {
    throw new Error('Use the opencli-managed browser (Strategy.INTERCEPT) — the current page object cannot capture network responses.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Running the command against a page object that lacks startNetworkCapture/readNetworkCapture (e.g. a plain browser-automation wrapper instead of the opencli CDP browser), passing a null/undefined page, or startNetworkCapture returning false because the CDP session could not attach a network listener.

Common situations: Invoking the command with a custom or mocked page in tests that only implement goto/evaluate; using an outdated opencli runtime whose browser doesn't expose capture APIs; running in an environment where CDP network domains can't be enabled (restricted browser, incompatible headless shell); a registry misconfiguration overriding the browser/strategy options.

Related errors


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