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
After navigating to the bus list URL, the CLI runs WAIT_FOR_BUS_JS in the page and inspects the returned state. If Ctrip's anti-bot layer serves a captcha instead of content, the CLI throws AuthRequiredError for bus.ctrip.com so the user can solve the captcha in their own authenticated browser session and retry.
Source
Thrown at clis/ctrip/bus.js:58
'departureTime',
'fromStation', 'toStation',
'duration', 'price', 'status',
'url',
],
func: async (page, kwargs) => {
const fromCity = parsePlaceName('from', kwargs.from);
const toCity = parsePlaceName('to', kwargs.to);
if (fromCity === toCity) {
throw new ArgumentError(`--from and --to must differ (got ${fromCity})`);
}
const date = parseIsoDate('date', kwargs.date);
const limit = parseListLimit(kwargs.limit);
const searchUrl = buildBusListUrl(fromCity, toCity, date);
await page.goto(searchUrl);
const waitResult = await page.evaluate(WAIT_FOR_BUS_JS);
if (waitResult === 'captcha') {
throw new AuthRequiredError('bus.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
}
if (waitResult !== 'content') {
throw new CommandExecutionError(`Ctrip bus page did not render schedule rows (state=${String(waitResult)})`);
}
const renderedCardCount = await page.evaluate(buildScrollUntilJs('.list-item-parent', limit));
const raw = await page.evaluate(buildBusExtractJs());
if (!Array.isArray(raw)) {
throw new CommandExecutionError('Ctrip bus DOM extraction returned malformed rows');
}
if (raw.length === 0) {
if (Number(renderedCardCount) > 0) {
throw new CommandExecutionError('Ctrip bus rows rendered but parser did not find required schedule anchors');
}
throw new EmptyResultError('ctrip bus', `No coaches for ${fromCity} to ${toCity} on ${date}`);
}
return raw.slice(0, limit).map((r, i) => ({
rank: i + 1,
departureTime: r.departureTime,View on GitHub (pinned to 49907e53dc)
Solutions
- Open the same browser session manually, solve the captcha on bus.ctrip.com, then rerun the command
- Reuse a persistent browser profile with valid Ctrip cookies instead of a fresh/headless one
- Slow down request rate and add delays between Ctrip queries
- Switch network/IP if your address is being flagged
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
rows = await ctripBusList({ from, to, date });
} catch (e) {
if (e instanceof AuthRequiredError && e.message.includes('captcha')) {
// Surface to the operator: manual captcha completion required, then retry once
await promptManualCaptchaResolution('bus.ctrip.com');
rows = await ctripBusList({ from, to, date });
} else {
throw e;
}
} Prevention
- Use a persistent, warmed-up browser profile with valid Ctrip cookies
- Rate-limit ctrip queries; add randomized delays between runs
- Avoid headless mode and datacenter IPs when scraping ctrip
- Catch AuthRequiredError distinctly and alert a human rather than blind-retrying
When it happens
Trigger: `clis ctrip bus` navigating to buildBusListUrl(...) and page.evaluate(WAIT_FOR_BUS_JS) returning the literal string 'captcha' — Ctrip flagged the session as automated or the shared browser profile is rate-limited.
Common situations: Running many bus queries in a short window (rate limiting); headless or fresh browser profile with no Ctrip cookies; datacenter IP flagged by Ctrip's WAF; Ctrip tightening anti-bot rules.
Related errors
- Ctrip is asking for a captcha; complete it in your browser s
- Ctrip is asking for a captcha; complete it in your browser s
- 请先在共享 Chrome 完成 1688 登录/验证,再重试(${action})
- Ctrip is asking for a captcha; complete it in your browser s
- Ctrip is asking for a captcha; complete it in your browser s
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a2530d3b6b4e9ada.
Report an issue: GitHub.