jackwener/OpenCLI · error · CommandExecutionError

Ctrip package page did not render package cards (state=${Str

Error message

Ctrip package page did not render package cards (state=${String(waitResult)})

What it means

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.

Source

Thrown at clis/ctrip/package.js:53

        'tags', 'score', 'sold', 'reviews',
        'price',
        'url',
    ],
    func: async (page, kwargs) => {
        const destination = parsePlaceName('destination', kwargs.destination);
        const limit = parseListLimit(kwargs.limit);

        const searchUrl = buildPackageListUrl(destination);
        await page.goto(searchUrl);
        const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);
        if (waitResult === 'captcha') {
            throw new AuthRequiredError('vacations.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
        }
        if (waitResult === 'empty') {
            throw new EmptyResultError('ctrip package', `No flight-plus-hotel packages for "${destination}"`);
        }
        if (waitResult !== 'content') {
            throw new CommandExecutionError(`Ctrip package page did not render package cards (state=${String(waitResult)})`);
        }
        const raw = await page.evaluate(buildVacationsExtractJs());
        if (!Array.isArray(raw)) {
            throw new CommandExecutionError('Ctrip package DOM extraction returned malformed rows');
        }
        if (raw.length === 0) {
            throw new CommandExecutionError('Ctrip package cards rendered but parser did not find required package anchors');
        }
        return raw.slice(0, limit).map((r, i) => ({
            rank: i + 1,
            title: r.title,
            subtitle: r.subtitle,
            tags: r.tags,
            score: r.score,
            sold: r.sold,
            reviews: r.reviews,
            price: r.price,
            url: searchUrl,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command; transient network/render slowness is the most common cause
  2. 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
  3. Verify vacations.ctrip.com renders .list_product_item cards in your browser session (Ctrip may have changed markup)
  4. Check your proxy/network stability for the headless browser
  5. Update the CLI package so WAIT_FOR_VACATIONS_JS matches current Ctrip markup

Example fix

// before
const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);
if (waitResult !== 'content') throw new CommandExecutionError(`state=${String(waitResult)}`);
// after
const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);
if (waitResult !== 'content') {
  await page.waitForSelector('.list_product_item', { timeout: 30000 }).catch(() => {});
  throw new CommandExecutionError(`state=${String(waitResult)}`);
}
Defensive patterns

Strategy: retry

Validate before calling

const dest = String(process.argv[2] || '').trim();
if (!dest) { console.error('destination required'); process.exit(1); }

Try / catch

try {
  const rows = await runCli('ctrip', 'package', dest);
} catch (e) {
  if (e.name === 'CommandExecutionError' && /state=/.test(e.message)) {
    await sleep(5000); // retry transient render failure
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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