{"record":{"id":"743bf288388992f4","repo":"jackwener/OpenCLI","slug":"trip-com-hotel-page-did-not-render-hotel-cards-st","errorCode":null,"errorMessage":"Trip.com hotel page did not render hotel cards (state=${String(waitResult)})","messagePattern":"Trip\\.com hotel page did not render hotel cards \\(state=(.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/trip/hotel-search.js","lineNumber":58,"sourceCode":"        'url',\n    ],\n    func: async (page, kwargs) => {\n        const cityId = parseCityId('city', kwargs.city);\n        const checkin = parseIsoDate('checkin', kwargs.checkin);\n        const checkout = parseIsoDate('checkout', kwargs.checkout);\n        if (checkin >= checkout) {\n            throw new ArgumentError(`--checkin must be before --checkout (got ${checkin} .. ${checkout})`);\n        }\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildHotelSearchUrl(cityId, checkin, checkout);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_HOTELS_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 hotel page did not render hotel cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildHotelExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com hotel DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new EmptyResultError('trip hotel-search', `No hotels for city ${cityId} on ${checkin} .. ${checkout}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            name: r.name,\n            score: r.score,\n            reviewLabel: r.reviewLabel,\n            reviews: r.reviews,\n            location: r.location,\n            room: r.room,\n            price: r.price,\n            currency: r.currency,","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/hotel-search.js#L40-L76","documentation":"This CommandExecutionError from clis/trip/hotel-search.js is thrown when WAIT_FOR_HOTELS_JS returns a state other than 'content' (and not 'captcha'), i.e. the hotel page loaded but hotel cards never rendered. The state string is embedded in the message (e.g. state=timeout) to identify what the waiter observed. This is a render/timing/layout problem distinct from CAPTCHA and from genuinely empty results.","triggerScenarios":"page.evaluate(WAIT_FOR_HOTELS_JS) after page.goto(searchUrl) returns 'timeout', 'error', or any unrecognized value; the extractor is never reached.","commonSituations":"Slow hotel-search pages (they are heavy) exceeding the waiter timeout; Trip.com changing hotel card markup so the selector never matches; headless browser resource limits stalling rendering; geo-redirects landing on an unexpected page variant.","solutions":["Check the state value in the message; for timeouts, increase the wait timeout before evaluating.","Load the same hotel search URL in a regular browser to confirm the page still renders hotel cards.","Update WAIT_FOR_HOTELS_JS selectors to match current Trip.com markup.","Retry off-peak or from a different network if rendering is unreliable."],"exampleFix":"// before\nconst waitResult = await page.evaluate(WAIT_FOR_HOTELS_JS);\nif (waitResult !== 'content') throw new CommandExecutionError(`... (state=${waitResult})`);\n// after\nlet waitResult = await page.evaluate(WAIT_FOR_HOTELS_JS);\nif (waitResult !== 'content') {\n  await page.waitForSelector(HOTEL_CARD_SELECTOR, { timeout: 30000 }).catch(() => {});\n  waitResult = await page.evaluate(WAIT_FOR_HOTELS_JS);\n}\nif (waitResult !== 'content') throw new CommandExecutionError(`... (state=${waitResult})`);","handlingStrategy":"retry","validationCode":"if (!/^[a-z-]+$/i.test(String(cityId)) && !/^\\d+$/.test(String(cityId))) throw new Error('invalid city id');\nif (!(new Date(checkin) < new Date(checkout))) throw new Error('bad date range');","typeGuard":"const isRenderFailure = (e) => e instanceof CommandExecutionError && /did not render hotel cards/.test(e.message);","tryCatchPattern":"try {\n  await runTripHotelSearch(args);\n} catch (e) {\n  if (isRenderFailure(e) && /state=timeout/.test(e.message)) {\n    await sleep(5000);\n    return runTripHotelSearch(args); // one bounded retry\n  }\n  throw e;\n}","preventionTips":["Allow long timeouts for hotel pages (they are resource-heavy).","Log state= values to distinguish timeout from layout drift.","Keep WAIT_FOR_HOTELS_JS in sync with Trip.com markup.","Retry timeouts once; investigate non-timeout states manually."],"tags":["scraping","timeout","dom-render","trip-com","hotels"],"backgroundTag":"page-render-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}