jackwener/OpenCLI · error · CommandExecutionError

Ctrip bus page did not render schedule rows (state=${String(

Error message

Ctrip bus page did not render schedule rows (state=${String(waitResult)})

What it means

The bus page load is considered successful only when WAIT_FOR_BUS_JS returns 'content'. Any other state (timeout, unknown selector state, navigation failure) means schedule rows never rendered, and the CLI throws CommandExecutionError including the raw state for debugging.

Source

Thrown at clis/ctrip/bus.js:61

        'url',
    ],
    func: async (page, kwargs) => {
        const fromCity = parsePlaceName('from', kwargs.from);
        const toCity = parsePlaceName('to', kwargs.to);
        if (fromCity === toCity) {
            throw new ArgumentError(`--from and --to must differ (got ${fromCity})`);
        }
        const date = parseIsoDate('date', kwargs.date);
        const limit = parseListLimit(kwargs.limit);

        const searchUrl = buildBusListUrl(fromCity, toCity, date);
        await page.goto(searchUrl);
        const waitResult = await page.evaluate(WAIT_FOR_BUS_JS);
        if (waitResult === 'captcha') {
            throw new AuthRequiredError('bus.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
        }
        if (waitResult !== 'content') {
            throw new CommandExecutionError(`Ctrip bus page did not render schedule rows (state=${String(waitResult)})`);
        }
        const renderedCardCount = await page.evaluate(buildScrollUntilJs('.list-item-parent', limit));
        const raw = await page.evaluate(buildBusExtractJs());
        if (!Array.isArray(raw)) {
            throw new CommandExecutionError('Ctrip bus DOM extraction returned malformed rows');
        }
        if (raw.length === 0) {
            if (Number(renderedCardCount) > 0) {
                throw new CommandExecutionError('Ctrip bus rows rendered but parser did not find required schedule anchors');
            }
            throw new EmptyResultError('ctrip bus', `No coaches for ${fromCity} to ${toCity} on ${date}`);
        }
        return raw.slice(0, limit).map((r, i) => ({
            rank: i + 1,
            departureTime: r.departureTime,
            fromStation: r.fromStation,
            toStation: r.toStation,
            duration: r.duration,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Rerun the command — transient slow loads often succeed on retry
  2. Check the `state=` value in the message and compare against the states WAIT_FOR_BUS_JS can return
  3. Increase the wait timeout inside WAIT_FOR_BUS_JS if your network is slow
  4. Update the wait script's selectors after a Ctrip DOM change

Example fix

// before
const waitResult = await page.evaluate(WAIT_FOR_BUS_JS);
// after (example: extend timeout in WAIT_FOR_BUS_JS)
const waitResult = await page.evaluate(WAIT_FOR_BUS_JS, { timeoutMs: 30000 });
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try {
  rows = await ctripBusList({ from, to, date });
} catch (e) {
  if (e instanceof CommandExecutionError && e.message.includes('did not render schedule rows')) {
    const state = /state=(\S+)/.exec(e.message)?.[1];
    console.error(`Bus page wait failed (state=${state}); retrying with backoff`);
    await sleep(3000);
    rows = await ctripBusList({ from, to, date });
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: `clis ctrip bus` where page.evaluate(WAIT_FOR_BUS_JS) returns anything other than 'captcha' or 'content' — e.g. a wait timeout, an error state string, or Ctrip serving a layout the wait script does not recognize.

Common situations: Slow network causing the wait script's timeout to fire; Ctrip DOM/A-B test redesign so expected schedule selectors never appear; page redirected to an interstitial or error page.

Related errors


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