{"record":{"id":"1fe95b15421c0ef0","repo":"jackwener/OpenCLI","slug":"ctrip-flight-api-response-body-was-unavailable","errorCode":null,"errorMessage":"Ctrip flight API response body was unavailable","messagePattern":"Ctrip flight API response body was unavailable","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/flight.js","lineNumber":78,"sourceCode":"    }\n    const captured = entries.filter((entry) => String(entry?.url || '').includes(CAPTURE_PATTERN));\n    if (captured.length === 0) return null;\n\n    const byId = new Map();\n    let finished = false;\n    for (const entry of captured) {\n        const status = Number(entry?.responseStatus || 0);\n        if (status === 401 || status === 403) {\n            throw new AuthRequiredError('flights.ctrip.com', `Ctrip flight API returned HTTP ${status}; complete any verification in the browser and retry`);\n        }\n        if (status !== 200) {\n            throw new CommandExecutionError(`Ctrip flight API returned HTTP ${status || 'unknown'}`);\n        }\n        if (entry?.responseBodyTruncated === true) {\n            throw new CommandExecutionError('Ctrip flight API response exceeded the browser capture limit');\n        }\n        if (typeof entry?.responsePreview !== 'string') {\n            throw new CommandExecutionError('Ctrip flight API response body was unavailable');\n        }\n        let payload;\n        try {\n            payload = JSON.parse(entry.responsePreview);\n        }\n        catch {\n            throw new CommandExecutionError('Ctrip flight API returned invalid JSON');\n        }\n        if (payload?.status !== 0) {\n            throw new CommandExecutionError(`Ctrip flight API failed (status=${String(payload?.status)}): ${cleanString(payload?.msg) || 'unknown error'}`);\n        }\n        const itineraries = payload?.data?.flightItineraryList;\n        if (!Array.isArray(itineraries) || typeof payload?.data?.context?.finished !== 'boolean') {\n            throw new CommandExecutionError('Ctrip flight API returned a malformed batchSearch payload');\n        }\n        for (const itinerary of itineraries) {\n            const id = cleanString(itinerary?.itineraryId);\n            if (!id) throw new CommandExecutionError('Ctrip flight API returned an itinerary without an id');","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/flight.js#L60-L96","documentation":"This CommandExecutionError is thrown when the captured batchSearch entry has no usable response body — responsePreview is not a string. The library captured the request metadata (URL, status) but could not retrieve the body, so there is nothing to parse. This indicates a capture-layer problem (browser closed, page navigated, CDP body fetch failed) rather than a Ctrip API error.","triggerScenarios":"A captured batchSearch entry where responsePreview is undefined/null/non-string — the page navigated away or the browser closed before the CDP getResponseBody call completed, or the capture harness failed to attach the body to the entry.","commonSituations":"Scripting the CLI so the browser/tab is closed as soon as results appear; SPA navigation away from the search page during capture; flaky CDP sessions (remote debugging disconnect); response body evicted from the browser cache before retrieval.","solutions":["Re-run the search and let the command complete normally before closing or navigating the browser.","Keep the automation browser and the target tab alive until the CLI exits.","Retry — if intermittent, it is likely a CDP/timing race; if consistent, inspect the capture harness version.","Ensure no extensions or navigation scripts redirect the page away from flights.ctrip.com mid-search."],"exampleFix":"// before: close browser as soon as output prints\nconst rows = await cli.itineraries(args);\nawait browser.close();\n// after: ensure CLI finishes before teardown\nconst rows = await cli.itineraries(args);\nprocess.on('exit', () => browser.close()); // or await cli completion promise first","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await cli.itineraries(args);\n} catch (err) {\n  if (/response body was unavailable/i.test(err.message || '')) {\n    // capture race: retry once after short delay, keep browser open\n    await sleep(2000);\n    return cli.itineraries(args);\n  }\n  throw err;\n}","preventionTips":["Never close or navigate the automation browser until the CLI command exits.","Avoid scripted navigation away from the search page mid-request.","Retry once on this error — it is usually a timing race in the capture layer.","Keep the remote-debugging (CDP) connection stable; avoid aggressive resource cleanup."],"tags":["cdp","capture-failure","browser-automation","response-body"],"backgroundTag":"response-body-unavailable","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}