{"record":{"id":"03442412a9493f01","repo":"jackwener/OpenCLI","slug":"currency-must-be-a-three-letter-iso-currency-code","errorCode":null,"errorMessage":"Currency must be a three-letter ISO currency code: ${currency}","messagePattern":"Currency must be a three-letter ISO currency code: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/mercury/utils.js","lineNumber":60,"sourceCode":"    }\n    if (!stat || !stat.isFile()) {\n        throw new ArgumentError(`Receipt file does not exist: ${receipt}`);\n    }\n    return receipt;\n}\n\nfunction parseAmount(kwargs) {\n    const amount = requireString(kwargs, 'amount').replace(/,/g, '');\n    if (!/^\\d+(\\.\\d{1,2})?$/.test(amount) || Number(amount) <= 0) {\n        throw new ArgumentError(`Amount must be a positive number with up to two decimals: ${amount}`);\n    }\n    return amount;\n}\n\nfunction parseCurrency(kwargs) {\n    const currency = optionalString(kwargs, 'currency', 'CNY').toUpperCase();\n    if (!/^[A-Z]{3}$/.test(currency)) {\n        throw new ArgumentError(`Currency must be a three-letter ISO currency code: ${currency}`);\n    }\n    return currency;\n}\n\nfunction parseDate(kwargs) {\n    const date = requireString(kwargs, 'date');\n    const match = date.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n    if (!match) {\n        throw new ArgumentError(`Date must be YYYY-MM-DD: ${date}`);\n    }\n    const year = Number(match[1]);\n    const month = Number(match[2]);\n    const day = Number(match[3]);\n    const parsed = new Date(Date.UTC(year, month - 1, day));\n    if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {\n        throw new ArgumentError(`Date must be a real calendar date: ${date}`);\n    }\n    return date;","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/utils.js#L42-L78","documentation":"parseCurrency upper-cases the currency option (default 'CNY') and requires exactly three ASCII letters A-Z. Any other value — longer codes, digits, symbols, non-Latin scripts, or empty after trimming — throws this ArgumentError.","triggerScenarios":"--currency 'us-dollars', 'USDT', '￥', 'CN Y', 'cny ' with a non-strippable char, or any string whose upper-case form is not exactly three A-Z letters.","commonSituations":"Passing crypto tickers (USDT) instead of ISO 4217 codes; including the currency symbol; locale-full names like 'yuan' or 'RMB' (note 'RMB' is 3 letters and would pass — but 'renminbi' would not); typos like 'CNY+'.","solutions":["Use the ISO 4217 alphabetic code: CNY, USD, EUR, JPY, etc.","Remove symbols, spaces, and punctuation from the value.","Omit --currency entirely if the default CNY is what you want.","Validate input upstream with /^[A-Za-z]{3}$/ before invoking."],"exampleFix":"// before\n--currency \"USDT\"\n// after\n--currency \"USD\"","handlingStrategy":"validation","validationCode":"function isValidCurrency(c) {\n  return typeof c === 'string' && /^[A-Za-z]{3}$/.test(c);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await reimburse({ currency });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('three-letter ISO currency code')) {\n    console.error(`'${currency}' is not ISO 4217; use codes like CNY, USD, EUR`);\n  } else throw e;\n}","preventionTips":["Always use ISO 4217 alphabetic codes","Uppercase/trim the value in wrapper scripts","Maintain an allowlist of supported currencies in your tooling","Omit the flag to accept the CNY default when appropriate"],"tags":["argument-validation","input-validation","currency","cli"],"backgroundTag":"invalid-input-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}