{"record":{"id":"5fe4259ea4a97f02","repo":"jackwener/OpenCLI","slug":"trip-com-train-timetable-did-not-render-state-s","errorCode":null,"errorMessage":"Trip.com train timetable did not render (state=${String(waitResult)}); check the city names and --country","messagePattern":"Trip\\.com train timetable did not render \\(state=(.+?)\\); check the city names and --country","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/trip/train.js","lineNumber":56,"sourceCode":"        'departureTime', 'fromStation',\n        'arrivalTime', 'toStation',\n        'duration', 'changes',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const from = parseKeyword('from', kwargs.from);\n        const to = parseKeyword('to', kwargs.to);\n        const country = parseKeyword('country', kwargs.country);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildTrainRouteUrl(country, from, to);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_TRAINS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('trip.com', 'Trip.com is asking for a verification; complete it in your browser session and retry');\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Trip.com train timetable did not render (state=${String(waitResult)}); check the city names and --country`);\n        }\n        const raw = await page.evaluate(buildTrainExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com train DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new EmptyResultError('trip train', `No timetable for ${from} to ${to} (${country})`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            departureTime: r.departureTime,\n            fromStation: r.fromStation,\n            arrivalTime: r.arrivalTime,\n            toStation: r.toStation,\n            duration: r.duration,\n            changes: r.changes,\n            url: searchUrl,\n        }));","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/train.js#L38-L74","documentation":"CommandExecutionError thrown when the Trip.com trains page was loaded but the timetable never reached a renderable state. The page.evaluate(WAIT_FOR_TRAINS_JS) probe returns a state string; anything other than 'content' (and other than 'captcha') means the results container never appeared. The state value is embedded in the message so you can see what the page actually did.","triggerScenarios":"Calling the trip train command with a from/to pair that Trip.com does not recognize (misspelled city, city not served by rail, or wrong --country), or the site layout/timing changed so the wait probe times out with 'timeout' or a similar non-content state.","commonSituations":"Typos in city names ('Londonn'), passing a city that only has an airport transfer service, omitting or mistyping --country so the URL resolves to a market without that route, slow page load exceeding the internal wait timeout, or Trip.com A/B redesigns breaking the wait selector.","solutions":["Check the city names passed via --from/--to and correct spelling; Trip.com needs its own city naming","Pass or correct --country so the search runs in the right Trip.com market","Retry once — transient slowness can make the wait probe time out","Read the state value in the message; if it is a timeout, increase patience/retry; if it is a layout-related state, update WAIT_FOR_TRAINS_JS selectors","Open the searchUrl in a browser to confirm the route exists on Trip.com"],"exampleFix":"// before\nawait runTripTrain({ from: 'Londn', to: 'Paris', country: 'UK' });\n// after\nawait runTripTrain({ from: 'London', to: 'Paris', country: 'GB' });","handlingStrategy":"retry","validationCode":"// pre-check inputs\nif (!from || !to) throw new Error('from/to required');\nconst known = ['london','paris','rome','madrid']; // your own allowlist\nif (!known.includes(from.toLowerCase())) console.warn(`verify '${from}' exists on trip.com trains`);","typeGuard":"function isWaitState(v) { return v === 'content' || v === 'captcha' || typeof v === 'string'; }","tryCatchPattern":"try {\n  const rows = await getTripTrains(args);\n} catch (e) {\n  if (/did not render \\(state=(\\w+)\\)/.test(e.message)) {\n    const state = e.message.match(/state=(\\w+)/)[1];\n    if (state === 'timeout') return retryOnce(args);\n  }\n  throw e;\n}","preventionTips":["Use exact Trip.com city spellings","Always pass --country for multi-market routes","Retry once on timeout states before failing","Verify the route manually in a browser for new city pairs"],"tags":["scraping","dom-render","trip-com","puppeteer"],"backgroundTag":"page-render-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}