jackwener/OpenCLI · error · AuthRequiredError
Ctrip is asking for a captcha; complete it in your browser s
Error message
Ctrip is asking for a captcha; complete it in your browser session and retry
What it means
Thrown as AuthRequiredError when the Ctrip train page presents a captcha instead of train results (the in-page wait script reports state 'captcha'). The library drives a persistent browser session and cannot solve captchas itself, so it defers to the user's interactive browser session. It signals that the session's cookies/fingerprint are no longer trusted by trains.ctrip.com.
Source
Thrown at clis/ctrip/train.js:57
'departureTime', 'departureStation',
'arrivalTime', 'arrivalStation',
'duration', 'fromPrice', 'seats',
'url',
],
func: async (page, kwargs) => {
const fromName = parsePlaceName('from', kwargs.from);
const toName = parsePlaceName('to', kwargs.to);
if (fromName === toName) {
throw new ArgumentError(`--from and --to must differ (got ${fromName})`);
}
const date = parseIsoDate('date', kwargs.date);
const limit = parseListLimit(kwargs.limit);
const searchUrl = buildTrainListUrl(fromName, toName, date);
await page.goto(searchUrl);
const waitResult = await page.evaluate(WAIT_FOR_TRAINS_JS);
if (waitResult === 'captcha') {
throw new AuthRequiredError('trains.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
}
if (waitResult !== 'content') {
throw new CommandExecutionError(`Ctrip train page did not render train cards (state=${String(waitResult)})`);
}
const renderedCardCount = await page.evaluate(buildScrollUntilJs('.card-white.list-item', limit));
const raw = await page.evaluate(buildTrainExtractJs());
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Ctrip train DOM extraction returned malformed rows');
}
if (raw.length === 0) {
if (Number(renderedCardCount) > 0) {
throw new CommandExecutionError('Ctrip train cards rendered but parser did not find required train anchors');
}
throw new EmptyResultError('ctrip train', `No trains for ${fromName} to ${toName} on ${date}`);
}
return raw.slice(0, limit).map((r, i) => ({
rank: i + 1,
trainNo: r.trainNo,View on GitHub (pinned to 49907e53dc)
Solutions
- Open the same browser session/user-data-dir interactively, solve the captcha on trains.ctrip.com, then retry the command.
- Reduce request rate and add delays between train queries.
- Use a residential IP or different network egress.
- Refresh the session by logging into Ctrip in the shared browser profile before retrying.
Example fix
// before (rapid loop)
for (const d of dates) await runTrainList({ from, to, date: d });
// after (throttled)
for (const d of dates) { await runTrainList({ from, to, date: d }); await sleep(15000); } Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try { await runTrainList(opts); } catch (e) { if (e instanceof AuthRequiredError) { await promptCaptchaSolve(e.domain); return retry(); } throw e; } Prevention
- Throttle requests to trains.ctrip.com
- Keep the shared browser profile logged in with fresh cookies
- Avoid datacenter IPs; prefer residential egress
- Solve captches promptly in the interactive session
When it happens
Trigger: page.goto(buildTrainListUrl(...)) followed by page.evaluate(WAIT_FOR_TRAINS_JS) returning 'captcha', typically after repeated automated requests or a stale/unauthenticated shared browser profile.
Common situations: Scraping many queries in quick succession; running from a datacenter IP; shared browser profile whose Ctrust cookies expired; Ctrip risk controls flagging headless/automated browsing.
Related errors
- Ctrip is asking for a captcha; complete it in your browser s
- Trip.com is asking for a verification; complete it in your b
- Trip.com is asking for a verification; complete it in your b
- Trip.com is asking for a verification; complete it in your b
- Trip.com is asking for a verification; complete it in your b
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ebdf9ebc4b5ed832.
Report an issue: GitHub.