jackwener/OpenCLI · info · EmptyResultError
ctrip hotel
Error message
ctrip hotel
What it means
EmptyResultError thrown when the extracted detail object exists but lacks hotelId or name — the minimum fields that constitute a usable hotel detail. The library treats a detail without identity fields as 'no detail exposed' for the given hotel id rather than returning partial data.
Source
Thrown at clis/ctrip/hotel.js:52
'url',
],
func: async (page, kwargs) => {
const hotelId = parseHotelId(kwargs.id);
const url = buildHotelDetailUrl(hotelId);
await page.goto(url);
const waitResult = await page.evaluate(WAIT_FOR_HOTEL_DETAIL_JS);
if (waitResult === 'captcha') {
throw new AuthRequiredError('hotels.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
}
if (waitResult !== 'content') {
throw new CommandExecutionError(`Ctrip hotel detail page did not expose SSR hotel data (state=${String(waitResult)})`);
}
const detail = await page.evaluate(buildHotelDetailExtractJs());
if (!detail || typeof detail !== 'object') {
throw new CommandExecutionError('Ctrip hotel detail SSR extraction returned malformed data');
}
if (!detail.hotelId || !detail.name) {
throw new EmptyResultError('ctrip hotel', `No detail exposed for hotel id ${hotelId}`);
}
return [{ ...detail, url }];
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Open the hotel URL in a browser to confirm the hotel page still exposes name/id
- Check the hotel id is current (re-run hotel-search to get fresh ids)
- Update mapHotelDetail/extract script if Ctrip renamed the fields
- Update the CLI to the latest version
Example fix
// before
if (!detail.hotelId || !detail.name) throw new EmptyResultError('ctrip hotel', `No detail exposed for hotel id ${hotelId}`);
// after
if (!detail.hotelId) detail.hotelId = String(hotelId); // fall back to the requested id
if (!detail.hotelId || !detail.name) throw new EmptyResultError('ctrip hotel', `No detail exposed for hotel id ${hotelId}`); Defensive patterns
Strategy: type-guard
Validate before calling
// after extraction, before relying on the detail
if (typeof detail?.name !== 'string' || !detail.name) console.warn(`hotel ${hotelId} exposes no name — possibly delisted`); Type guard
const isUsableDetail = (d) => !!d && typeof d === 'object' && !!d.hotelId && typeof d.name === 'string' && d.name.length > 0;
Try / catch
try {
return await ctrip.hotel({ id });
} catch (e) {
if (e instanceof EmptyResultError) {
return null; // hotel has no exposed detail — treat as not found
}
throw e;
} Prevention
- Refresh hotel ids via hotel-search before fetching details
- Verify delisted hotels manually in a browser
- Fallback to requested id when only hotelId is missing
- Track empty-detail rates per id source
When it happens
Trigger: buildHotelDetailExtractJs() returns an object whose hotelId/name keys are absent or empty: the page rendered but the identity block (title/hotel id) uses new markup, or the hotel is delisted and renders a shell page.
Common situations: Querying a closed/renamed hotel whose page still resolves; Ctrip renaming identity fields in its SSR payload; overseas/regional variants omitting these fields; stale CLI after a Ctrip update.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- 1point3acres thread
- 1point3acres user
- amazon ${definition.commandName} did not expose any ranked i
- amazon search did not expose any product cards
- No posts found in this Band
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/be92d6153fa2e94b.
Report an issue: GitHub.