{"record":{"id":"409ba45059955f95","repo":"jackwener/OpenCLI","slug":"no-detail-exposed-for-hotel-id-hotelid","errorCode":null,"errorMessage":"No detail exposed for hotel id ${hotelId}","messagePattern":"No detail exposed for hotel id (.+?)","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/trip/hotel.js","lineNumber":50,"sourceCode":"        'url',\n    ],\n    func: async (page, kwargs) => {\n        const hotelId = parseHotelId('id', kwargs.id);\n        const url = buildHotelDetailUrl(hotelId);\n        await page.goto(url);\n        const waitResult = await page.evaluate(WAIT_FOR_HOTEL_DETAIL_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 detail page did not expose SSR hotel data (state=${String(waitResult)})`);\n        }\n        const detail = await page.evaluate(buildHotelDetailExtractJs());\n        if (!detail || typeof detail !== 'object') {\n            throw new CommandExecutionError('Trip.com hotel detail SSR extraction returned malformed data');\n        }\n        if (!detail.hotelId || !detail.name) {\n            throw new EmptyResultError('trip hotel', `No detail exposed for hotel id ${hotelId}`);\n        }\n        return [{ ...detail, url }];\n    },\n});\n","sourceCodeStart":32,"sourceCodeEnd":55,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/hotel.js#L32-L55","documentation":"This EmptyResultError is thrown when the SSR extraction returned a valid object but its hotelId or name fields are missing/empty — Trip.com exposed a detail payload without the core identity fields. Effectively, the site has no usable detail data for this hotel id.","triggerScenarios":"detail.hotelId or detail.name is falsy after buildHotelDetailExtractJs(): invalid/unpublished hotel ids, delisted properties, or region-redirected pages that render a shell without identity data.","commonSituations":"Scraping a hotel id copied from an outdated listing, hotels removed from Trip.com inventory, or geo-mismatched sessions where the site serves a stub page.","solutions":["Verify the hotel id resolves to a live Trip.com hotel page in a browser","Refresh the hotel id from a current trip hotel-search result","Retry with a session whose geo/locale matches the hotel's region","Catch EmptyResultError and skip the hotel as unavailable"],"exampleFix":"// before\nfor (const id of ids) results.push(await tripHotelDetail({ id }));\n// after\nfor (const id of ids) {\n  try { results.push(await tripHotelDetail({ id })); }\n  catch (e) { if (e instanceof EmptyResultError) continue; throw e; }\n}","handlingStrategy":"fallback","validationCode":"const known = await hotelSearch({ cityId });\nif (!known.some(h => String(h.hotelId) === String(hotelId))) {\n  throw new Error(`hotel ${hotelId} not in current Trip.com inventory`);\n}","typeGuard":"function hasIdentity(detail) {\n  return Boolean(detail) && typeof detail === 'object' &&\n    Boolean(detail.hotelId) && Boolean(detail.name);\n}","tryCatchPattern":"try {\n  return await tripHotelDetail({ id });\n} catch (e) {\n  if (e instanceof EmptyResultError) return null; // skip delisted hotel\n  throw e;\n}","preventionTips":["Source hotel ids from a current search, not stale bookmarks","Skip-and-continue batch scraping when one hotel lacks detail data","Retry region-locked ids with a matching geo/locale session","Check the hotel page in a browser when a detail lookup repeatedly returns empty"],"tags":["scraping","empty-results","ssr","trip-com","hotels"],"backgroundTag":"empty-scrape-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}