{"record":{"id":"0966b9a2b50166cc","repo":"jackwener/OpenCLI","slug":"ctrip-bus-page-did-not-render-schedule-rows-state","errorCode":null,"errorMessage":"Ctrip bus page did not render schedule rows (state=${String(waitResult)})","messagePattern":"Ctrip bus page did not render schedule rows \\(state=(.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/bus.js","lineNumber":61,"sourceCode":"        'url',\n    ],\n    func: async (page, kwargs) => {\n        const fromCity = parsePlaceName('from', kwargs.from);\n        const toCity = parsePlaceName('to', kwargs.to);\n        if (fromCity === toCity) {\n            throw new ArgumentError(`--from and --to must differ (got ${fromCity})`);\n        }\n        const date = parseIsoDate('date', kwargs.date);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildBusListUrl(fromCity, toCity, date);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_BUS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('bus.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip bus page did not render schedule rows (state=${String(waitResult)})`);\n        }\n        const renderedCardCount = await page.evaluate(buildScrollUntilJs('.list-item-parent', limit));\n        const raw = await page.evaluate(buildBusExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip bus DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            if (Number(renderedCardCount) > 0) {\n                throw new CommandExecutionError('Ctrip bus rows rendered but parser did not find required schedule anchors');\n            }\n            throw new EmptyResultError('ctrip bus', `No coaches for ${fromCity} to ${toCity} on ${date}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            departureTime: r.departureTime,\n            fromStation: r.fromStation,\n            toStation: r.toStation,\n            duration: r.duration,","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/bus.js#L43-L79","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Rerun the command — transient slow loads often succeed on retry","Check the `state=` value in the message and compare against the states WAIT_FOR_BUS_JS can return","Increase the wait timeout inside WAIT_FOR_BUS_JS if your network is slow","Update the wait script's selectors after a Ctrip DOM change"],"exampleFix":"// before\nconst waitResult = await page.evaluate(WAIT_FOR_BUS_JS);\n// after (example: extend timeout in WAIT_FOR_BUS_JS)\nconst waitResult = await page.evaluate(WAIT_FOR_BUS_JS, { timeoutMs: 30000 });","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  rows = await ctripBusList({ from, to, date });\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('did not render schedule rows')) {\n    const state = /state=(\\S+)/.exec(e.message)?.[1];\n    console.error(`Bus page wait failed (state=${state}); retrying with backoff`);\n    await sleep(3000);\n    rows = await ctripBusList({ from, to, date });\n  } else {\n    throw e;\n  }\n}","preventionTips":["Retry once or twice with backoff before failing — slow loads are the most common cause","Log the embedded `state=` value for diagnosis","Keep WAIT_FOR_BUS_JS selectors/timeout updated against live ctrip markup","Set conservative timeouts suited to your network conditions"],"tags":["dom-render","ctrip","timeout","scraping"],"backgroundTag":"page-did-not-render-expected-content","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}