{"record":{"id":"1addbf5c5330e2a0","repo":"jackwener/OpenCLI","slug":"ctrip-tour-page-did-not-render-package-cards-stat","errorCode":null,"errorMessage":"Ctrip tour page did not render package cards (state=${String(waitResult)})","messagePattern":"Ctrip tour page did not render package cards \\(state=(.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/tour.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 = buildTourListUrl(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 tour', `No tour packages for \"${destination}\"`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip tour 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 tour DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Ctrip tour 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/tour.js#L35-L71","documentation":"A CommandExecutionError raised by `ctrip tour` when the wait helper returned an unrecognized state (neither 'captcha', 'empty', nor 'content'), meaning the tour search page finished loading without rendering package cards. The state value is embedded in the message for diagnosis. The library cannot distinguish navigation failure, timeout, or markup change, so it fails with the observed state.","triggerScenarios":"Running `opencli ctrip tour <destination>` where page.evaluate(WAIT_FOR_VACATIONS_JS) resolves to an unexpected value — timeouts waiting for .list_product_item, evaluate errors returning undefined/null, or the page redirecting away from the results view.","commonSituations":"Slow network leaving results unrendered before the helper's timeout; Ctrip A/B or redesign removing polled selectors; headless environments where lazy hydration never completes; intermittent evaluate failures.","solutions":["Re-run the command — transient render slowness is common","Inspect the state=... value in the message to identify which branch of WAIT_FOR_VACATIONS_JS produced it","Confirm .list_product_item cards appear on the tour search URL in a real browser","Stabilize your network/proxy for the headless browser","Update the CLI so the wait helper matches current Ctrip markup"],"exampleFix":"// before\nif (waitResult !== 'content') throw new CommandExecutionError(`state=${String(waitResult)}`);\n// after\nif (waitResult !== 'content') {\n  await page.waitForSelector('.list_product_item', { timeout: 30000 }).catch(() => {});\n  if (!(await page.$('.list_product_item'))) 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 tours = await runCli('ctrip', 'tour', 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":["Retry with backoff — slow rendering is the usual cause","Inspect the state= value for fast diagnosis","Keep the CLI's WAIT_FOR_VACATIONS_JS current with Ctrip markup","Ensure reliable network/proxy for the headless browser"],"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"}