{"record":{"id":"b8574d64b94530be","repo":"jackwener/OpenCLI","slug":"ctrip-flight-requires-browser-response-interceptio","errorCode":null,"errorMessage":"Ctrip flight requires browser response interception","messagePattern":"Ctrip flight requires browser response interception","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/flight.js","lineNumber":183,"sourceCode":"        'price', 'currency', 'cabin',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const fromCode = parseIataCode('from', kwargs.from);\n        const toCode = parseIataCode('to', kwargs.to);\n        if (fromCode === toCode) {\n            throw new ArgumentError(`--from and --to must differ (got ${fromCode})`);\n        }\n        const date = parseIsoDate('date', kwargs.date);\n        const limit = parseFlightLimit(kwargs.limit);\n\n        const searchUrl =\n            `https://flights.ctrip.com/online/list/oneway-${fromCode.toLowerCase()}-${toCode.toLowerCase()}` +\n            `?depdate=${date}&cabin=Y_S_C_F&adult=1&child=0&infant=0`;\n        if (typeof page?.startNetworkCapture !== 'function' ||\n            typeof page?.readNetworkCapture !== 'function' ||\n            !await page.startNetworkCapture(CAPTURE_PATTERN)) {\n            throw new CommandExecutionError('Ctrip flight requires browser response interception');\n        }\n        await page.readNetworkCapture();\n        await page.goto(searchUrl);\n        // The initial document can finish before the large batchSearch body.\n        // The first rendered card is only a readiness signal; row data still\n        // comes exclusively from the structured response below.\n        const readiness = await page.evaluate(WAIT_FOR_BATCH_CAPTURE_JS);\n        if (readiness === 'captcha') {\n            throw new AuthRequiredError('flights.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        const itineraries = parseBatchSearchCaptures(await page.readNetworkCapture());\n        if (!itineraries) {\n            throw new TimeoutError('Ctrip flight API capture', CAPTURE_TIMEOUT_SECONDS, 'No batchSearch response was observed after opening the results page.');\n        }\n        if (itineraries.length === 0) {\n            throw new EmptyResultError('ctrip flight', `No flights for ${fromCode}→${toCode} on ${date}`);\n        }\n        const rows = itineraries","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/flight.js#L165-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run the command through the standard opencli browser (browser: true, Strategy.INTERCEPT) so page gets startNetworkCapture/readNetworkCapture.","Upgrade @jackwener/opencli to a version whose browser exposes the network capture APIs.","If testing, stub page.startNetworkCapture (returning true) and page.readNetworkCapture in your mock page object.","Check that the CDP session can enable network interception (no restricted browser/extension blocking Fetch/Network domains)."],"exampleFix":"// before: plain puppeteer page handed to the command\nconst page = await browser.newPage();\nawait runCommand('ctrip flight', { page });\n\n// after: use the opencli-managed page with capture support\nconst page = await opencliBrowser.newPage({ intercept: true });\nawait runCommand('ctrip flight', { page });","handlingStrategy":"type-guard","validationCode":"// Verify capture support before invoking the command\nfunction supportsInterception(page) {\n  return typeof page?.startNetworkCapture === 'function' &&\n         typeof page?.readNetworkCapture === 'function';\n}\nif (!supportsInterception(page)) throw new Error('page lacks network capture APIs');","typeGuard":"function isInterceptCapablePage(page) {\n  return page != null &&\n    typeof page.startNetworkCapture === 'function' &&\n    typeof page.readNetworkCapture === 'function' &&\n    typeof page.goto === 'function' &&\n    typeof page.evaluate === 'function';\n}","tryCatchPattern":"try {\n  const rows = await ctripFlight({ from, to, date });\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('requires browser response interception')) {\n    throw new Error('Use the opencli-managed browser (Strategy.INTERCEPT) — the current page object cannot capture network responses.');\n  }\n  throw e;\n}","preventionTips":["Always run intercept-strategy commands through the opencli-managed browser.","In tests, stub startNetworkCapture/readNetworkCapture on mock page objects.","Upgrade opencli when browser capture APIs change between versions.","Smoke-test page capabilities (typeof checks) before dispatching commands."],"tags":["browser","network-interception","cdp","environment"],"backgroundTag":"browser-interception-unsupported","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}