jackwener/OpenCLI · warning · ArgumentError

--checkin must be earlier than --checkout (got ${checkin} >=

Error message

--checkin must be earlier than --checkout (got ${checkin} >= ${checkout})

What it means

A client-side ArgumentError from assertCheckinBeforeCheckout: the `ctrip hotel-search` command requires --checkin to be strictly earlier than --checkout. Both are parsed as ISO dates and compared at UTC midnight; if checkin >= checkout (equal dates included), the command refuses to build the hotels.ctrip.com URL, since Ctrip's list endpoint cannot serve a zero/negative-length stay.

Source

Thrown at clis/ctrip/hotel-search.js:64

      const result = detect();
      if (result) { observer.disconnect(); resolve(result); }
    });
    observer.observe(document.documentElement, { childList: true, subtree: true });
    setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 5000);
  })
`;

const EXTRACT_HOTELS_JS = `
  (() => {
    const list = window.__NEXT_DATA__?.props?.pageProps?.initListData?.hotelList;
    if (!Array.isArray(list)) return null;
    return list;
  })()
`;

function assertCheckinBeforeCheckout(checkin, checkout) {
    if (Date.parse(checkin + 'T00:00:00Z') >= Date.parse(checkout + 'T00:00:00Z')) {
        throw new ArgumentError(`--checkin must be earlier than --checkout (got ${checkin} >= ${checkout})`);
    }
}

cli({
    site: 'ctrip',
    name: 'hotel-search',
    access: 'read',
    description: '搜索携程酒店列表(按城市 + 入住/离店日期)',
    domain: 'hotels.ctrip.com',
    strategy: Strategy.COOKIE,
    browser: true,
    navigateBefore: false,
    args: [
        { name: 'city', required: true, positional: true, help: 'Numeric Ctrip city ID (use `ctrip search` or `ctrip hotel-suggest` to discover)' },
        { name: 'checkin', required: true, help: 'Check-in date (YYYY-MM-DD)' },
        { name: 'checkout', required: true, help: 'Check-out date (YYYY-MM-DD)' },
        { name: 'limit', default: DEFAULT_LIMIT, help: `Number of hotels (${MIN_LIMIT}-${MAX_LIMIT}); SSR first page returns ~13 entries` },
    ],

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass checkout strictly after checkin, e.g. --checkin 2026-09-01 --checkout 2026-09-02 for one night.
  2. Validate the pair in your calling code before invoking the command.
  3. If dates come from user input, normalize and sort them (earlier date = checkin) before calling.

Example fix

// before
await hotelSearch({ city: '1', checkin: '2026-09-05', checkout: '2026-09-01' });

// after: normalize order first
if (checkin >= checkout) [checkin, checkout] = [checkout, checkin];
await hotelSearch({ city: '1', checkin, checkout });
Defensive patterns

Strategy: validation

Validate before calling

function validateStay(checkin, checkout) {
  const ci = Date.parse(checkin + 'T00:00:00Z');
  const co = Date.parse(checkout + 'T00:00:00Z');
  if (!(co > ci)) throw new Error(`checkout must be after checkin (got ${checkin} >= ${checkout})`);
}
validateStay(checkin, checkout);

Try / catch

try {
  const rows = await ctripHotelSearch({ city, checkin, checkout });
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('earlier than')) {
    console.error(`Bad date range: ${e.message}`); process.exitCode = 2; return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `ctrip hotel-search <city> --checkin 2026-09-01 --checkout 2026-09-01` (same-day) or with checkout earlier than checkin (swapped order, e.g. --checkin 2026-09-05 --checkout 2026-09-01).

Common situations: Swapping the two arguments in scripts; generating a single-night stay using the same date for both fields; date arithmetic off-by-one producing checkout <= checkin; timezone-shifted strings where the author assumed a different comparison basis.

Related errors


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