jackwener/OpenCLI · error · ArgumentError
Date must be a real calendar date: ${date}
Error message
Date must be a real calendar date: ${date} What it means
After the YYYY-MM-DD shape check passes, parseDate constructs a UTC Date and verifies the components round-trip (year/month/day unchanged). This rejects impossible calendar dates like 2026-02-31 or 2025-13-01, which the regex alone would accept. JavaScript's Date silently rolls such values over, so the round-trip check is the real validity gate.
Source
Thrown at clis/mercury/utils.js:76
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}`);
}
const year = Number(match[1]);
const month = Number(match[2]);
const day = Number(match[3]);
const parsed = new Date(Date.UTC(year, month - 1, day));
if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {
throw new ArgumentError(`Date must be a real calendar date: ${date}`);
}
return date;
}
function parseOcrWaitSeconds(kwargs) {
const raw = optionalString(kwargs, 'ocr-wait-seconds', '8');
if (!/^\d+$/.test(raw)) {
throw new ArgumentError(`ocr-wait-seconds must be a non-negative integer: ${raw}`);
}
return Number(raw);
}
export function normalizeReimbursementInput(kwargs) {
return {
receipt: parseReceiptPath(kwargs),
amount: parseAmount(kwargs),
currency: parseCurrency(kwargs),
date: parseDate(kwargs),View on GitHub (pinned to 49907e53dc)
Solutions
- Correct the date to a real calendar date (check the month's day count).
- Generate dates programmatically instead of hardcoding: new Date(Date.UTC(y,m-1,d)).toISOString().slice(0,10).
- If constructing from zero-indexed months in JS, add 1 to the month before formatting.
- Validate upstream with a calendar-aware check (e.g. Date round-trip) before calling.
Example fix
// before --date "2026-02-30" // after --date "2026-02-28"
Defensive patterns
Strategy: validation
Validate before calling
function isRealDate(d) {
const m = /^\d{4}-\d{2}-\d{2}$/.exec(d);
if (!m) return false;
const dt = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3]));
return dt.getUTCFullYear() === +m[1] && dt.getUTCMonth() === +m[2] - 1 && dt.getUTCDate() === +m[3];
} Try / catch
try {
await reimburse({ date });
} catch (e) {
if (e instanceof ArgumentError && e.message.includes('real calendar date')) {
console.error(`'${date}' is not a valid calendar date (e.g. Feb 30).`);
} else throw e;
} Prevention
- Derive dates from Date arithmetic, not hand-typed literals
- Remember JS months are 0-indexed when constructing dates
- Validate month/day ranges before submitting forms
- Use a date library (or this round-trip check) in upstream tooling
When it happens
Trigger: --date '2026-02-30', '2026-02-31', '2025-13-01', '2026-00-10', '2026-04-31' — syntactically valid shape but not a real date.
Common situations: Hand-typed dates with wrong day counts (February 30/31); month off-by-one from zero-indexed month values in generated scripts; day 31 in 30-day months; scripts computing dates incorrectly before passing them in.
Related errors
- ${label} must be a non-negative integer, got ${JSON.stringif
- limit must be a positive integer
- archive wayback timestamp must be YYYY[MM[DD[hh[mm[ss]]]]] o
- archive wayback url cannot be empty
- bilibili comment ${label} must be a positive integer
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5e334b33648ff56b.
Report an issue: GitHub.