{"record":{"id":"263b47bcc439f7a1","repo":"jackwener/OpenCLI","slug":"city-unknown-city-cityarg-pass-a-guazi-city","errorCode":null,"errorMessage":"city unknown city '${cityArg}'. pass a Guazi city code or one of: ${names}","messagePattern":"city unknown city '(.+?)'\\. pass a Guazi city code or one of: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/guazi/utils.js","lineNumber":66,"sourceCode":"    zhengzhou: 'zz', '郑州': 'zz',\n    changsha: 'cs', '长沙': 'cs',\n    qingdao: 'qd', '青岛': 'qd',\n    shenyang: 'sy', '沈阳': 'sy',\n    dalian: 'dl', '大连': 'dl',\n    jinan: 'jn', '济南': 'jn',\n    hefei: 'hf', '合肥': 'hf',\n    foshan: 'fs', '佛山': 'fs',\n};\n\n/** Resolve a city arg (name or code) to a Guazi city code; defaults to bj. */\nexport function resolveCityCode(cityArg) {\n    if (cityArg == null || cityArg === '') return 'bj';\n    const raw = String(cityArg).trim().toLowerCase();\n    if (CITY_CODE[raw]) return CITY_CODE[raw];\n    if (CITY_CODE[String(cityArg).trim()]) return CITY_CODE[String(cityArg).trim()];\n    if (/^[a-z]{2,3}$/.test(raw)) return raw; // already a code\n    const names = Object.keys(CITY_CODE).filter((k) => /^[a-z]+$/.test(k)).join(', ');\n    throw new ArgumentError('city', `unknown city '${cityArg}'. pass a Guazi city code or one of: ${names}`);\n}\n\n/** Normalize a clue id: a bare number or a /car-detail/c<id>.htm(l) URL. */\nexport function normalizeClueId(rawInput) {\n    const raw = String(rawInput || '').trim();\n    if (!raw) throw new ArgumentError('clue_id must be a non-empty value');\n    const m = raw.match(/car-detail\\/c(\\d+)/) || raw.match(/^c?(\\d+)$/);\n    if (!m) {\n        throw new ArgumentError(`'${rawInput}' does not look like a guazi clue id (a number, or a /car-detail/c<id>.html URL)`);\n    }\n    return m[1];\n}\n\nexport function requireLimit(value, def, max) {\n    const raw = value == null || value === '' ? def : value;\n    const n = typeof raw === 'number' ? raw : Number(String(raw).trim());\n    if (!Number.isInteger(n) || n < 1 || n > max) {\n        throw new ArgumentError(`limit must be an integer between 1 and ${max}`);","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/guazi/utils.js#L48-L84","documentation":"resolveCityCode maps a user-supplied city argument to a Guazi city code. It accepts known city names/codes from CITY_CODE or any 2-3 letter lowercase code (assumed to already be a code); anything else throws this ArgumentError listing the valid name keys. Default when empty is 'bj' (Beijing).","triggerScenarios":"Calling any guazi command with --city 'beijing' spelled as an unknown full name not in CITY_CODE, e.g. --city \"上海\" (Chinese characters), --city 'Beijing China', or a 4+ letter word like 'guangz'.","commonSituations":"Passing a Chinese city name when the table only has pinyin keys; passing a full English name ('shanghai' works but 'shanghais' does not); passing a numeric postal code; typos in the pinyin code.","solutions":["Pass a valid code from the listed names (e.g. bj, sh) or a 2-3 letter lowercase code.","Look at the error message's list of accepted names and pick one exactly.","Add the missing city mapping to CITY_CODE in clis/guazi/utils.js if your city is legitimately missing.","Normalize your input (trim, lowercase) before passing it — e.g. ' BJ ' works because of trim/lowercase, 'BJ ' as-is also handled, but 'beijing ' variants may not be in the table."],"exampleFix":"// before\nguazi browse --city \"上海\"\n// after\nguazi browse --city sh","handlingStrategy":"validation","validationCode":"const VALID = new Set(Object.keys(CITY_CODE));\nfunction isValidCityArg(v) {\n  if (v == null || v === '') return true; // defaults to bj\n  const raw = String(v).trim().toLowerCase();\n  return VALID.has(raw) || /^[a-z]{2,3}$/.test(raw);\n}","typeGuard":"function isCityCode(v) {\n  return typeof v === 'string' && /^[a-z]{2,3}$/.test(v.trim().toLowerCase());\n}","tryCatchPattern":"try {\n  const code = resolveCityCode(cityArg);\n} catch (e) {\n  if (/unknown city/.test(e.message)) {\n    console.error(e.message);\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Use pinyin codes (bj, sh) from the error's accepted list","Normalize to lowercase and trim before passing","Extend CITY_CODE when a needed city is missing","Avoid passing Chinese characters or full English names"],"tags":["argument-validation","cli","city-code"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}