jackwener/OpenCLI · error · ArgumentError

--city is required (numeric city ID from `ctrip search` or `

Error message

--city is required (numeric city ID from `ctrip search` or `ctrip hotel-suggest`)

What it means

parseCityId requires the --city flag to be present and non-blank: undefined, null, empty or whitespace-only strings are rejected. The value must be a numeric Ctrip city ID (a positive integer obtained from `ctrip search` or `ctrip hotel-suggest`). It throws ArgumentError immediately so the caller knows to supply an ID rather than a city name.

Source

Thrown at clis/ctrip/utils.js:251

 * Ctrip URL accepts both single-airport (PEK / PVG) and metro-group (BJS / SHA) codes.
 */
export function parseIataCode(name, raw) {
    if (raw === undefined || raw === null || raw === '') {
        throw new ArgumentError(`--${name} is required (3-letter IATA code, e.g. PEK, SHA)`);
    }
    const value = String(raw).trim().toUpperCase();
    if (!/^[A-Z]{3}$/.test(value)) {
        throw new ArgumentError(`--${name} must be a 3-letter IATA code, got ${JSON.stringify(raw)}`);
    }
    return value;
}

/**
 * Validate a numeric Ctrip city ID (returned by `ctrip search` / `ctrip hotel-suggest`).
 */
export function parseCityId(raw) {
    if (raw === undefined || raw === null || raw === '' || String(raw).trim() === '') {
        throw new ArgumentError('--city is required (numeric city ID from `ctrip search` or `ctrip hotel-suggest`)');
    }
    try {
        return parseStrictPositiveInteger('city', raw);
    } catch {
        throw new ArgumentError(`--city must be a positive integer city ID, got ${JSON.stringify(raw)}`);
    }
}

/**
 * Pick the best lat/lon from a Ctrip hotel `positionInfo.mapCoordinate` array.
 *
 * Each entry has a `coordinateType` (1=WGS84, 2=GCJ02, 3=BD09 / Baidu). We prefer
 * WGS84 when present (most portable), then fall through. All coordinates are
 * strings in the API, so we Number() and reject NaN.
 */
export function pickHotelMapCoords(mapCoordinate) {
    if (!Array.isArray(mapCoordinate) || mapCoordinate.length === 0) {
        return { lat: null, lon: null };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Run `ctrip search <name>` or `ctrip hotel-suggest` first and pass the returned numeric city ID to --city.
  2. Make sure --city is actually set and not an empty shell variable.
  3. Do not pass a Chinese city name; only numeric IDs are accepted (names go through other flags like parsePlaceName).

Example fix

// before
ctrip hotels --city "上海"
// after
const id = await ctripSearchCityId('上海'); // e.g. 1
ctrip hotels --city 1
Defensive patterns

Strategy: validation

Validate before calling

if (cityId === undefined || cityId === null || String(cityId).trim() === '') {
  throw new Error('--city is required: run `ctrip search` to get a numeric city ID');
}

Type guard

const isPresent = (v) => v !== undefined && v !== null && String(v).trim() !== '';

Try / catch

try {
  const id = parseCityId(raw);
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('--city is required')) {
    console.error('Provide --city <numericId> from `ctrip search`.');
  } else throw e;
}

Prevention

When it happens

Trigger: Running a ctrip hotel command with --city omitted entirely, or with --city "" / --city " " (empty or whitespace after shell expansion).

Common situations: Users pass a city NAME like '上海' to --city instead of the numeric ID, or an unset environment variable expands to empty. IDs must come from `ctrip search` / `ctrip hotel-suggest`, so skipping that lookup step triggers this.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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