jackwener/OpenCLI · error · ArgumentError
Amount must be a positive number with up to two decimals: ${
Error message
Amount must be a positive number with up to two decimals: ${amount} What it means
parseAmount strips commas and validates the amount string against ^\d+(\.\d{1,2})?$ and requires it be > 0. Anything with symbols, currency codes, thousands separators other than commas, exponents, negatives, or more than two decimals is rejected with this ArgumentError.
Source
Thrown at clis/mercury/utils.js:52
function parseReceiptPath(kwargs) {
const receipt = path.resolve(requireString(kwargs, 'receipt'));
let stat;
try {
stat = fs.statSync(receipt, { throwIfNoEntry: false });
}
catch (error) {
throw new ArgumentError(`Receipt file cannot be read: ${receipt}`, error instanceof Error ? error.message : undefined);
}
if (!stat || !stat.isFile()) {
throw new ArgumentError(`Receipt file does not exist: ${receipt}`);
}
return receipt;
}
function parseAmount(kwargs) {
const amount = requireString(kwargs, 'amount').replace(/,/g, '');
if (!/^\d+(\.\d{1,2})?$/.test(amount) || Number(amount) <= 0) {
throw new ArgumentError(`Amount must be a positive number with up to two decimals: ${amount}`);
}
return amount;
}
function parseCurrency(kwargs) {
const currency = optionalString(kwargs, 'currency', 'CNY').toUpperCase();
if (!/^[A-Z]{3}$/.test(currency)) {
throw new ArgumentError(`Currency must be a three-letter ISO currency code: ${currency}`);
}
return currency;
}
function parseDate(kwargs) {
const date = requireString(kwargs, 'date');
const match = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (!match) {
throw new ArgumentError(`Date must be YYYY-MM-DD: ${date}`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Supply the amount as a plain decimal string with '.' as the decimal separator and no currency symbols: e.g. '1234.56'.
- Remove thousands separators before passing (or use commas only as thousands separators, which the parser strips).
- Round/trim to at most two decimal places and ensure the value is greater than zero.
- If amounts come from another system, sanitize them first: strip symbols, convert ',' decimals to '.', then format with toFixed(2).
Example fix
// before --amount "¥1,234.567" // after --amount "1234.57"
Defensive patterns
Strategy: validation
Validate before calling
function isValidAmount(a) {
const s = String(a).replace(/,/g, '');
return /^\d+(\.\d{1,2})?$/.test(s) && Number(s) > 0;
} Try / catch
try {
await reimburse({ amount });
} catch (e) {
if (e instanceof ArgumentError && e.message.includes('Amount must be a positive number')) {
console.error('Expected format: digits with optional .xx, e.g. 1234.56');
} else throw e;
} Prevention
- Strip currency symbols before passing amounts
- Convert European '1.234,56' formats to '1234.56' first
- Round money to 2 decimals with toFixed(2) upstream
- Never pass negative or zero amounts to reimbursement
When it happens
Trigger: amount values like '$12.50', '12,50' (European decimal comma, comma stripped leaving 1250), '-3', '0', '0.00', '12.345', '1e3', or empty string after comma removal.
Common situations: Copy-pasting amounts from invoices that include currency symbols; European number formatting using '.' as thousands separator ('1.234,56' -> '1234,56' fails); passing numbers with 3+ decimals from spreadsheets.
Related errors
- ${label} must be a non-negative integer, got ${JSON.stringif
- limit must be a positive integer
- bilibili comment ${label} must be a positive integer
- bilibili comment message cannot be empty
- bilibili unfollow target cannot be empty
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/e0a5e059d041f304.
Report an issue: GitHub.