{"record":{"id":"c540ff27537f05ea","repo":"jackwener/OpenCLI","slug":"ctrip-package-page-did-not-render-package-cards-s","errorCode":null,"errorMessage":"Ctrip package page did not render package cards (state=${String(waitResult)})","messagePattern":"Ctrip package page did not render package cards \\(state=(.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/package.js","lineNumber":53,"sourceCode":"        'tags', 'score', 'sold', 'reviews',\n        'price',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const destination = parsePlaceName('destination', kwargs.destination);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildPackageListUrl(destination);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('vacations.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult === 'empty') {\n            throw new EmptyResultError('ctrip package', `No flight-plus-hotel packages for \"${destination}\"`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip package page did not render package cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildVacationsExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip package DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Ctrip package cards rendered but parser did not find required package anchors');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            title: r.title,\n            subtitle: r.subtitle,\n            tags: r.tags,\n            score: r.score,\n            sold: r.sold,\n            reviews: r.reviews,\n            price: r.price,\n            url: searchUrl,","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/package.js#L35-L71","documentation":"Raised by the `ctrip package` CLI command when the vacations.ctrip.com freetravel search page finishes loading in a state that is neither 'captcha', 'empty', nor 'content'. The WAIT_FOR_VACATIONS_JS helper returned an unexpected value, meaning package cards never rendered. The library treats any non-recognized wait state as a command execution failure rather than a result-level condition.","triggerScenarios":"Running `opencli ctrip package <destination>` when page.goto succeeds but page.evaluate(WAIT_FOR_VACATIONS_JS) returns a value other than 'captcha'/'empty'/'content' — e.g. network timeout inside the wait helper, page navigated away mid-wait, or the evaluate returning null/undefined due to a JS error in the page context.","commonSituations":"Slow or throttled Ctrip CDN leaving the results container unmounted; Ctrip front-end redesign that removes the selector WAIT_FOR_VACATIONS_JS polls; headless-browser environments where lazy-loaded results never hydrate; intermittent page.evaluate failures after redirect chains.","solutions":["Re-run the command; transient network/render slowness is the most common cause","Check the state value in the message (state=...) to see what the wait helper actually returned and debug that branch in WAIT_FOR_VACATIONS_JS","Verify vacations.ctrip.com renders .list_product_item cards in your browser session (Ctrip may have changed markup)","Check your proxy/network stability for the headless browser","Update the CLI package so WAIT_FOR_VACATIONS_JS matches current Ctrip markup"],"exampleFix":"// before\nconst waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);\nif (waitResult !== 'content') throw new CommandExecutionError(`state=${String(waitResult)}`);\n// after\nconst waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);\nif (waitResult !== 'content') {\n  await page.waitForSelector('.list_product_item', { timeout: 30000 }).catch(() => {});\n  throw new CommandExecutionError(`state=${String(waitResult)}`);\n}","handlingStrategy":"retry","validationCode":"const dest = String(process.argv[2] || '').trim();\nif (!dest) { console.error('destination required'); process.exit(1); }","typeGuard":null,"tryCatchPattern":"try {\n  const rows = await runCli('ctrip', 'package', dest);\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && /state=/.test(e.message)) {\n    await sleep(5000); // retry transient render failure\n  } else throw e;\n}","preventionTips":["Run on a stable network; avoid flaky proxies for the headless browser","Keep the CLI updated so the wait helper tracks Ctrip markup changes","Add retry-with-backoff around browser-based ctrip commands","Read the state= value in the error to diagnose quickly"],"tags":["browser-automation","dom-rendering","scraping","ctrip"],"backgroundTag":"page-render-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}