jackwener/OpenCLI · error · ArgumentError

--city must be a positive integer city ID, got ${JSON.string

Error message

--city must be a positive integer city ID, got ${JSON.stringify(raw)}

What it means

After the presence check, parseCityId delegates to parseStrictPositiveInteger('city', raw); if that fails (non-numeric, float, negative, zero, or numeric with junk like '12abc'), it rethrows as ArgumentError '--city must be a positive integer city ID'. The value must be a strictly positive integer matching Ctrip's city ID scheme.

Source

Thrown at clis/ctrip/utils.js:256

    }
    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 };
    }
    // Order: WGS84 (1) → GCJ02 (2) → BD09 (3) → whatever exists
    const ranking = (entry) => {
        const t = Number(entry?.coordinateType);
        if (t === 1) return 0;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run `ctrip search` / `ctrip hotel-suggest` and copy the exact numeric city ID.
  2. Trim the value and remove any non-digit characters before passing it.
  3. Use a positive integer >= 1; zero, negatives, decimals and exponent notation are rejected.

Example fix

// before
ctrip hotels --city 12.5
// after
ctrip hotels --city 2
Defensive patterns

Strategy: validation

Validate before calling

const n = Number(String(raw).trim());
if (!Number.isInteger(n) || n < 1) throw new Error('--city must be a positive integer, got ' + raw);

Type guard

const isPositiveInt = (v) => typeof v === 'number' ? Number.isInteger(v) && v > 0 : /^\d+$/.test(String(v).trim());

Try / catch

try {
  const cityId = parseCityId(raw);
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('positive integer')) {
    console.error('Copy the numeric ID exactly from `ctrip search` output.');
  } else throw e;
}

Prevention

When it happens

Trigger: Passing --city with a non-integer or invalid number: 'abc', '1.5', '0', '-3', '12 ', '1e3', or values with attached units like 'city=2'.

Common situations: Typo'd or hand-guessed city IDs, pasted IDs with trailing spaces or invisible characters, decimal/negative numbers, or mixing up hotel IDs with city IDs.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


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