jackwener/OpenCLI · error · AuthRequiredError
hotels.ctrip.com
Error message
hotels.ctrip.com
What it means
AuthRequiredError thrown when the Ctrip hotel detail page presents a captcha instead of hotel content. WAIT_FOR_HOTEL_DETAIL_JS returns 'captcha' and the library signals that the user must complete the captcha in a real browser session before automated access can continue. It is not retryable automatically.
Source
Thrown at clis/ctrip/hotel.js:42
browser: true,
navigateBefore: false,
args: [
{ name: 'id', required: true, positional: true, help: 'Numeric Ctrip hotel id (use `ctrip hotel-suggest` to discover; e.g. 375539)' },
],
columns: [
'hotelId', 'name', 'enName',
'star', 'score', 'scoreLabel', 'reviewCount', 'ratingBreakdown',
'facilities', 'checkInOut',
'cityName', 'address', 'lat', 'lon',
'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 same browser session, solve the captcha, then retry the command
- Refresh/re-login the persistent browser profile the CLI uses
- Slow down request rate and add delays between detail fetches
- Switch to a residential IP or different network
Example fix
// before
await ctrip.hotel({ id: hotelId }); // throws AuthRequiredError when captcha'd
// after
try {
return await ctrip.hotel({ id: hotelId });
} catch (e) {
if (e instanceof AuthRequiredError) {
await openBrowserForManualCaptcha(); // user completes captcha in session
return await ctrip.hotel({ id: hotelId });
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// no pre-call validation possible; detect captcha state after load instead const state = await page.evaluate(WAIT_FOR_HOTEL_DETAIL_JS); if (state === 'captcha') await requireManualCaptchaResolution();
Type guard
const isAuthRequiredError = (e) => e instanceof AuthRequiredError || e?.name === 'AuthRequiredError';
Try / catch
try {
return await ctrip.hotel({ id });
} catch (e) {
if (isAuthRequiredError(e)) {
await promptUserToSolveCaptcha(); // interactive browser session
return await ctrip.hotel({ id }); // single retry after manual solve
}
throw e;
} Prevention
- Keep the browser session cookies fresh
- Throttle detail-page requests and add jittered delays
- Avoid datacenter IPs; prefer residential networks
- Pause scraping when consecutive captcha errors occur
When it happens
Trigger: page.evaluate(WAIT_FOR_HOTEL_DETAIL_JS) resolves with 'captcha' after page.goto(buildHotelDetailUrl(hotelId)) — Ctrip's anti-bot layer detected automation, the session cookies are stale/blocked, or the IP is rate-limited.
Common situations: Scraping too fast from a datacenter IP; expired connect-browser session cookies; running headless without a fingerprint; repeated detail-page requests in a loop.
Related errors
- vacations.ctrip.com
- guazi ${contextHint} hit an anti-bot challenge — Guazi may h
- [taxonomy=selector_drift] site=powerchina command=search log
- Trip.com is asking for a verification; complete it in your b
- 请先在共享 Chrome 完成 1688 登录/验证,再重试(${action})
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/eb1c5adf85716c64.
Report an issue: GitHub.