jackwener/OpenCLI · warning · AuthRequiredError
hotels.ctrip.com
Error message
hotels.ctrip.com
What it means
An AuthRequiredError raised when the hotels.ctrip.com list page signals a captcha gate: the WAIT_FOR_SSR_JS probe detected the page path containing 'captcha' or anti-bot text (验证码, verify the human) instead of SSR hotel data in window.__NEXT_DATA__. The domain string 'hotels.ctrip.com' is the error's first argument and becomes the message. It means risk control intercepted the visit and a human session must clear the challenge.
Source
Thrown at clis/ctrip/hotel-search.js:101
columns: [
'rank', 'hotelId', 'name', 'enName',
'star', 'score', 'scoreLabel', 'reviewCount',
'cityName', 'district', 'address',
'lat', 'lon',
'price', 'currency', 'url',
],
func: async (page, kwargs) => {
const cityId = parseCityId(kwargs.city);
const checkin = parseIsoDate('checkin', kwargs.checkin);
const checkout = parseIsoDate('checkout', kwargs.checkout);
assertCheckinBeforeCheckout(checkin, checkout);
const limit = parseHotelLimit(kwargs.limit);
const url = `https://hotels.ctrip.com/hotels/list?city=${cityId}&checkin=${checkin}&checkout=${checkout}`;
await page.goto(url);
const waitResult = await page.evaluate(WAIT_FOR_SSR_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-search page did not expose SSR hotel list (state=${String(waitResult)})`);
}
const raw = await page.evaluate(EXTRACT_HOTELS_JS);
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Ctrip hotel-search returned malformed SSR hotel list');
}
if (raw.length === 0) {
throw new EmptyResultError('ctrip hotel-search', `No hotels for city=${cityId} on ${checkin} → ${checkout}`);
}
const rows = raw
.map((entry, i) => mapHotelRow(entry, i))
.filter((row) => row.hotelId && row.name)
.slice(0, limit);
if (rows.length === 0) {
throw new CommandExecutionError('Ctrip hotel-search SSR rows were missing required hotelId/name anchors');
}View on GitHub (pinned to 49907e53dc)
Solutions
- Complete the captcha in your linked human browser session, then rerun the command.
- Slow down: add delays between city searches and avoid large sequential batches.
- Reuse a logged-in Ctrip browser profile so traffic carries trusted cookies.
- Switch to a residential IP if datacenter IPs are consistently flagged.
Example fix
// before: 50 cities back-to-back from an anonymous profile
for (const city of cities) await hotelSearch({ city, checkin, checkout });
// after: warm session + throttle
await browserLogin('ctrip');
for (const city of cities) {
await hotelSearch({ city, checkin, checkout });
await sleep(3000 + Math.random() * 4000);
} Defensive patterns
Strategy: retry
Try / catch
try {
const rows = await ctripHotelSearch({ city, checkin, checkout });
} catch (e) {
if (e instanceof AuthRequiredError && e.message.includes('hotels.ctrip.com')) {
await notifyHuman('Ctrip captcha on hotels.ctrip.com — complete it in the browser session');
return retryWithBackoff(() => ctripHotelSearch({ city, checkin, checkout }), { max: 2 });
}
throw e;
} Prevention
- Reuse a logged-in, cookie-persistent browser profile for automated hotel queries.
- Throttle bulk city searches with randomized delays.
- Avoid datacenter IPs; use residential connections where possible.
- Pause the whole workflow at the first captcha instead of continuing to other cities.
When it happens
Trigger: Navigating to https://hotels.ctrip.com/hotels/list?city=...&checkin=...&checkout=... when Ctrip redirects to /captcha or overlays a verification prompt — typically from flagged IPs, rapid repeated queries, or anonymous browser profiles without trusted cookies.
Common situations: Bulk city queries in a loop from a datacenter IP; CI environments with no persistent cookies; shared proxies previously abused; new/unwarmed browser profiles; Ctrip tightening risk control during peak travel periods.
Related errors
- flights.ctrip.com
- dianping.com
- 请先在共享 Chrome 完成 1688 登录/验证,再重试(${action})
- ${config.site} login
- Browser session required for bilibili follow
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0a5c6189bdb42927.
Report an issue: GitHub.