jackwener/OpenCLI · error · ArgumentError
currency must be a 3-letter ISO code (e.g. USD, JPY, CNY), g
Error message
currency must be a 3-letter ISO code (e.g. USD, JPY, CNY), got ${JSON.stringify(value)} What it means
normalizeCurrency validates the optional currency parameter as a 3-letter A-Z code (uppercased and trimmed first). It throws ArgumentError when a non-empty currency value is not exactly three letters after normalization. It does not validate ISO-4217 membership — only the shape — so '' or null are allowed (meaning default) but 'US' or 'USDD' are rejected.
Source
Thrown at clis/booking/search.js:59
}
const [year, month, day] = v.split('-').map(Number);
const d = new Date(Date.UTC(year, month - 1, day));
if (
Number.isNaN(d.getTime()) ||
d.getUTCFullYear() !== year ||
d.getUTCMonth() !== month - 1 ||
d.getUTCDate() !== day
) {
throw new ArgumentError(`${label} is not a valid calendar date: ${v}`);
}
return v;
}
function normalizeCurrency(value) {
if (value == null || value === '') return '';
const v = String(value).trim().toUpperCase();
if (!/^[A-Z]{3}$/.test(v)) {
throw new ArgumentError(`currency must be a 3-letter ISO code (e.g. USD, JPY, CNY), got ${JSON.stringify(value)}`);
}
return v;
}
const ALLOWED_LANGS = new Set([
'en-us', 'en-gb', 'zh-cn', 'zh-tw', 'ja', 'ko', 'de', 'fr', 'es', 'it',
'pt-br', 'pt-pt', 'ru', 'th', 'vi', 'tr', 'pl', 'nl', 'ar',
]);
function normalizeLang(value) {
if (value == null || value === '') return '';
const v = String(value).trim().toLowerCase();
if (!ALLOWED_LANGS.has(v)) {
throw new ArgumentError(`lang must be one of: ${[...ALLOWED_LANGS].join(', ')}`);
}
return v;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Change the value to the 3-letter ISO 4217 code, e.g. 'USD', 'JPY', 'CNY'
- Trim surrounding whitespace and remove symbols from the config/env value
- Validate shape with /^[A-Za-z]{3}$/ before calling
- Check the source system is not emitting numeric ISO codes and map 840 -> USD if so
Example fix
// before
const currency = '$';
await search(page, { destination: 'Tokyo', currency });
// after
const currency = 'USD';
await search(page, { destination: 'Tokyo', currency }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalizeCurrencySafe(v) {
if (v == null || v === '') return '';
const s = String(v).trim().toUpperCase();
if (!/^[A-Z]{3}$/.test(s)) throw new Error(`bad currency: ${v}`);
return s;
} Type guard
function isCurrencyCode(v) {
return typeof v === 'string' && /^[A-Za-z]{3}$/.test(v.trim());
} Try / catch
try {
await search(page, { destination, currency });
} catch (e) {
if (/3-letter ISO code/.test(e.message)) {
throw new Error(`Set currency to a 3-letter ISO code like USD; got: ${currency}`);
} else throw e;
} Prevention
- Store alphabetic ISO 4217 codes ('USD'), never symbols or names
- Uppercase and trim currency values at the config boundary
- Map numeric ISO codes to alphabetic ones if your source uses them
- Keep currency as an optional field only when defaults are acceptable
When it happens
Trigger: Passing currency values like 'US', 'us-dollar', '$', 'USDollar', or numbers to the search command; a config value that contains a currency symbol or full currency name instead of the code.
Common situations: Using '$' or '€' from UI input; storing 'US Dollar' in a settings file; concatenating a numeric code (840) instead of the alphabetic code; trailing whitespace/full-width characters in config.
Related errors
- coingecko has no market totals for currency "${currency}"
- 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
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/14c3671d80c2bde4.
Report an issue: GitHub.