jackwener/OpenCLI · error · ArgumentError
unknown city '${cityArg}'. pass a numeric cityId or one of:
Error message
unknown city '${cityArg}'. pass a numeric cityId or one of: ${names} What it means
resolveCityId resolves the --city argument to a numeric dianping cityId by accepting a digit string or a key of the CITY_ID map (English or Chinese names). If the argument is non-numeric and not a known city key, the library throws this ArgumentError listing all accepted English city names. A null/empty argument is allowed and means 'use the cookie's default city', so this error only fires for a genuinely unrecognized name.
Source
Thrown at clis/dianping/utils.js:59
xiamen: 15, '厦门': 15,
hefei: 110, '合肥': 110,
};
export const SEARCH_COLUMNS = ['rank', 'shop_id', 'name', 'rating', 'reviews', 'price', 'cuisine', 'district', 'url'];
export const SHOP_COLUMNS = ['field', 'value'];
/**
* Resolve a city argument (name or id) to a numeric cityId.
* Returns null when the cookie's default city should be used.
*/
export function resolveCityId(cityArg) {
if (cityArg == null || cityArg === '') return null;
const raw = String(cityArg).trim().toLowerCase();
if (/^\d+$/.test(raw)) return Number(raw);
const id = CITY_ID[raw];
if (!id) {
const names = Object.keys(CITY_ID).filter((k) => /^[a-z]+$/.test(k)).join(', ');
throw new ArgumentError(
'city',
`unknown city '${cityArg}'. pass a numeric cityId or one of: ${names}`,
);
}
return id;
}
export function requireSearchLimit(value) {
const raw = value == null || value === '' ? 15 : value;
const limit = typeof raw === 'number' ? raw : Number(String(raw).trim());
if (!Number.isInteger(limit) || limit < 1 || limit > 15) {
throw new ArgumentError('limit must be an integer between 1 and 15 (dianping single page)');
}
return limit;
}
export function normalizeShopId(rawInput) {
const raw = String(rawInput || '').trim();View on GitHub (pinned to 49907e53dc)
Solutions
- Use one of the listed English names exactly (beijing, shanghai, guangzhou, shenzhen, hangzhou, chengdu, chongqing, nanjing, suzhou, xian, wuhan, tianjin, qingdao, changsha, dalian, shenyang, kunming, fuzhou, xiamen, hefei).
- Look up the numeric cityId on dianping.com (/citylist or the /search/keyword/{cityId}/... URL) and pass the number instead — any digit string is accepted.
- Check for typos, extra whitespace, or full-width characters; the lookup lowercases and trims but does not fuzzy-match or accept pinyin variants.
- Extend the CITY_ID map (or open an issue/PR) if your city is supported by dianping but missing from the built-in list.
Example fix
// before
resolveCityId('shenzen'); // ArgumentError: unknown city
// after
resolveCityId('shenzhen'); // 7
// or pass the numeric id directly
resolveCityId('7'); // 7 Defensive patterns
Strategy: validation
Validate before calling
const KNOWN = ['beijing','shanghai','guangzhou','shenzhen','hangzhou','chengdu','chongqing','nanjing','suzhou','xian','wuhan','tianjin','qingdao','changsha','dalian','shenyang','kunming','fuzhou','xiamen','hefei'];
function isValidCityArg(v) {
if (v == null || v === '') return true; // default city
const raw = String(v).trim().toLowerCase();
return /^\d+$/.test(raw) || KNOWN.includes(raw);
} Type guard
function isCityArg(v) {
return typeof v === 'string' && (/^\d+$/.test(v.trim()) || CITY_ID.hasOwnProperty(v.trim().toLowerCase()));
} Try / catch
try {
const cityId = resolveCityId(cityArg);
} catch (e) {
if (e.name === 'ArgumentError' && String(e.message).startsWith('unknown city')) {
console.error(`City '${cityArg}' not in built-in map; pass a numeric cityId from dianping /citylist`);
} else throw e;
} Prevention
- Always pass numeric cityIds in scripts — names depend on the built-in 20-city map.
- Copy cityIds from the dianping /search/keyword/{cityId}/... URL structure.
- Normalize inputs: trim, lowercase, avoid full-width characters from CJK input methods.
- Omit the city argument entirely to use the cookie's default city.
When it happens
Trigger: Passing a city name not in the CITY_ID map (e.g. 'newyork', 'suzhou ' typos aside, 'guangdong', '东莞市', pinyin like 'shenzhenshi'), a misspelled name such as 'xian ' vs 'xian' works but 'xi\u2019an' or 'sian' does not, or passing a Chinese name variant that differs from the map keys.
Common situations: Typo in city name; passing a province or district instead of a supported city; passing a city dianping supports but this small built-in map omits (the map only has 20 common cities); locale/input-method issues producing full-width characters.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- archive search sort must be one of ${SORT_OPTIONS.join(', ')
- archive search mediatype must be one of ${MEDIATYPES.join(',
- archive search limit must be a positive integer
- archive search limit must be <= 100
- archive search query must not be empty
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7bcfbc80aa3b5531.
Report an issue: GitHub.