{"record":{"id":"732d69776a5e66bc","repo":"jackwener/OpenCLI","slug":"name-must-be-a-numeric-trip-com-city-id-got","errorCode":null,"errorMessage":"--${name} must be a numeric Trip.com city id, got ${JSON.stringify(raw)}","messagePattern":"--(.+?) must be a numeric Trip\\.com city id, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/trip/utils.js","lineNumber":248,"sourceCode":"    };\n    const found = detect();\n    if (found) return resolve(found);\n    const observer = new MutationObserver(() => {\n      const result = detect();\n      if (result) { observer.disconnect(); resolve(result); }\n    });\n    observer.observe(document.documentElement, { childList: true, subtree: true });\n    setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 12000);\n  })\n`;\n\nexport function parseCityId(name, raw) {\n    if (raw === undefined || raw === null || String(raw).trim() === '') {\n        throw new ArgumentError(`--${name} is required (numeric Trip.com city id, e.g. 338 for London)`);\n    }\n    const value = String(raw).trim();\n    if (!/^\\d+$/.test(value)) {\n        throw new ArgumentError(`--${name} must be a numeric Trip.com city id, got ${JSON.stringify(raw)}`);\n    }\n    return value;\n}\n\nexport function buildHotelSearchUrl(cityId, checkin, checkout) {\n    const params = new URLSearchParams({\n        city: cityId,\n        checkin,\n        checkout,\n        locale: 'en_US',\n        curr: 'USD',\n    });\n    return `https://www.trip.com/hotels/list?${params.toString()}`;\n}\n\n/**\n * Browser-context IIFE that extracts hotel rows from Trip.com's rendered\n * `.hotel-card` cards, read by stable class-keyed fields","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/utils.js#L230-L266","documentation":"parseCityId throws this when a value was provided but is not entirely digits (/^\\d+$/ fails). Trip.com city ids are pure numeric strings; names, IATA codes, or ids with letters/punctuation are rejected.","triggerScenarios":"Passing --city-id LON, --city-id 'city:338', --city-id 338.0, --city-id '338 ', handled by trim, so this fires on things like 'ID338', 'London', negative numbers '-338', or decimal '338.5'.","commonSituations":"Confusing IATA codes with Trip.com numeric ids; copy-pasting an id with a label prefix; receiving an id from an API as a float-formatted number ('338.0'); encoding a name where an id is expected.","solutions":["Use the numeric id only, e.g. --city-id 338","Convert an IATA code/city name to the Trip.com numeric id via the city search/listing first","Strip non-digit characters if the id comes embedded in a string ('city:338' -> '338')","If a number arrives as 338.0 from JSON, use String(Math.trunc(x)) to normalize"],"exampleFix":"// before\nclis-trip hotels --city-id LON --checkin 2026-10-01 --checkout 2026-10-05\n// after\nclis-trip hotels --city-id 338 --checkin 2026-10-01 --checkout 2026-10-05","handlingStrategy":"validation","validationCode":"function isNumericId(v) {\n  return typeof v === 'string' && /^\\d+$/.test(v.trim());\n}\nif (!isNumericId(String(cityId))) throw new Error(`--city-id must be numeric, got ${JSON.stringify(cityId)}`);","typeGuard":"function isNumericCityId(v) {\n  return /^\\d+$/.test(String(v).trim());\n}","tryCatchPattern":"try {\n  runTripCli(['hotels', '--city-id', cityId]);\n} catch (err) {\n  if (err instanceof ArgumentError && /must be a numeric Trip\\.com city id/.test(err.message)) {\n    console.error(`--city-id must be digits only (e.g. 338), got: ${err.message}`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Convert IATA codes or city names to numeric Trip.com ids before calling","Normalize ids coming from APIs (Math.trunc to drop '.0')","Strip label prefixes when copy-pasting ids","Validate with /^\\d+$/ at the boundary"],"tags":["cli","argument-validation","trip-com"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}