{"record":{"id":"b413660494642ca8","repo":"jackwener/OpenCLI","slug":"city-is-required-numeric-city-id-from-ctrip-se","errorCode":null,"errorMessage":"--city is required (numeric city ID from `ctrip search` or `ctrip hotel-suggest`)","messagePattern":"--city is required \\(numeric city ID from `ctrip search` or `ctrip hotel-suggest`\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":251,"sourceCode":" * Ctrip URL accepts both single-airport (PEK / PVG) and metro-group (BJS / SHA) codes.\n */\nexport function parseIataCode(name, raw) {\n    if (raw === undefined || raw === null || raw === '') {\n        throw new ArgumentError(`--${name} is required (3-letter IATA code, e.g. PEK, SHA)`);\n    }\n    const value = String(raw).trim().toUpperCase();\n    if (!/^[A-Z]{3}$/.test(value)) {\n        throw new ArgumentError(`--${name} must be a 3-letter IATA code, got ${JSON.stringify(raw)}`);\n    }\n    return value;\n}\n\n/**\n * Validate a numeric Ctrip city ID (returned by `ctrip search` / `ctrip hotel-suggest`).\n */\nexport function parseCityId(raw) {\n    if (raw === undefined || raw === null || raw === '' || String(raw).trim() === '') {\n        throw new ArgumentError('--city is required (numeric city ID from `ctrip search` or `ctrip hotel-suggest`)');\n    }\n    try {\n        return parseStrictPositiveInteger('city', raw);\n    } catch {\n        throw new ArgumentError(`--city must be a positive integer city ID, got ${JSON.stringify(raw)}`);\n    }\n}\n\n/**\n * Pick the best lat/lon from a Ctrip hotel `positionInfo.mapCoordinate` array.\n *\n * Each entry has a `coordinateType` (1=WGS84, 2=GCJ02, 3=BD09 / Baidu). We prefer\n * WGS84 when present (most portable), then fall through. All coordinates are\n * strings in the API, so we Number() and reject NaN.\n */\nexport function pickHotelMapCoords(mapCoordinate) {\n    if (!Array.isArray(mapCoordinate) || mapCoordinate.length === 0) {\n        return { lat: null, lon: null };","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L233-L269","documentation":"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.","triggerScenarios":"Running a ctrip hotel command with --city omitted entirely, or with --city \"\" / --city \"   \" (empty or whitespace after shell expansion).","commonSituations":"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.","solutions":["Run `ctrip search <name>` or `ctrip hotel-suggest` first and pass the returned numeric city ID to --city.","Make sure --city is actually set and not an empty shell variable.","Do not pass a Chinese city name; only numeric IDs are accepted (names go through other flags like parsePlaceName)."],"exampleFix":"// before\nctrip hotels --city \"上海\"\n// after\nconst id = await ctripSearchCityId('上海'); // e.g. 1\nctrip hotels --city 1","handlingStrategy":"validation","validationCode":"if (cityId === undefined || cityId === null || String(cityId).trim() === '') {\n  throw new Error('--city is required: run `ctrip search` to get a numeric city ID');\n}","typeGuard":"const isPresent = (v) => v !== undefined && v !== null && String(v).trim() !== '';","tryCatchPattern":"try {\n  const id = parseCityId(raw);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('--city is required')) {\n    console.error('Provide --city <numericId> from `ctrip search`.');\n  } else throw e;\n}","preventionTips":["Always run `ctrip search` / `ctrip hotel-suggest` first and store the numeric ID.","Check shell variables are non-empty before interpolating into flags (${VAR:?} in bash).","Never pass city names to --city; names belong to the search step."],"tags":["cli","validation","argument-error","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}