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

  1. Open the same browser session, solve the captcha, then retry the command
  2. Refresh/re-login the persistent browser profile the CLI uses
  3. Slow down request rate and add delays between detail fetches
  4. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/eb1c5adf85716c64. Report an issue: GitHub.