actualbudget/actual · error
Invalid end date format
Error message
Invalid end date format
What it means
calendarSpreadsheet parses the report's 'end' month string (yyyy-MM) into a yyyy-MM-dd day string and then into a Date via date-fns parse. If that parse throws (malformed month string), the function rethrows a wrapped 'Invalid end date format' error instead of letting date-fns leak through. It exists to give report consumers a clear signal that the configured date range cannot be used to build the calendar query.
Source
Thrown at packages/desktop-client/src/components/reports/spreadsheets/calendar-spreadsheet.ts:74
monthUtils.firstDayOfMonth(start),
'yyyy-MM-dd',
new Date(),
);
} catch (error) {
console.error('Failed to parse start date:', error);
throw new Error('Invalid start date format');
}
let endDay: Date;
try {
endDay = d.parse(
monthUtils.lastDayOfMonth(end),
'yyyy-MM-dd',
new Date(),
);
} catch (error) {
console.error('Failed to parse end date:', error);
throw new Error('Invalid end date format');
}
const makeRootQuery = () =>
q('transactions')
.filter({
$and: [
{ date: { $gte: d.format(startDay, 'yyyy-MM-dd') } },
{ date: { $lte: d.format(endDay, 'yyyy-MM-dd') } },
],
})
.filter({
[conditionsOpKey]: filters,
})
.groupBy(['date'])
.select(['date', { amount: { $sum: '$amount' } }]);
let expenseData;
try {View on GitHub (pinned to d4334cb6e6)
Solutions
- Log/inspect the end value being passed to calendarSpreadsheet and correct it to a valid 'yyyy-MM' month string
- Validate the end date with a regex like /^\d{4}-\d{2}$/ and monthUtils.getMonth before calling calendarSpreadsheet
- If the value comes from saved report config, reset or re-save the report's date range in the UI
- Wrap the calendarSpreadsheet call in try/catch and fall back to a default range (e.g. current year)
Example fix
// before
calendarSpreadsheet(start, '2024/05', conditions, locale);
// after
const end = '2024-05'; // valid yyyy-MM
if (!/^\d{4}-\d{2}$/.test(end)) throw new Error('end must be yyyy-MM');
calendarSpreadsheet(start, end, conditions, locale); Defensive patterns
Strategy: validation
Validate before calling
const isValidMonth = (s: string) => /^\d{4}-(0[1-9]|1[0-2])$/.test(s);
if (!isValidMonth(end)) throw new RangeError(`end must be yyyy-MM, got: ${end}`); Type guard
function isValidMonthString(v: unknown): v is string {
return typeof v === 'string' && /^\d{4}-(0[1-9]|1[0-2])$/.test(v);
} Try / catch
try {
await calendarSpreadsheet(start, end, conditions, locale)(spreadsheet, setData);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid end date format') {
console.warn('Falling back to default range', e);
await calendarSpreadsheet(start, defaultEnd, conditions, locale)(spreadsheet, setData);
} else throw e;
} Prevention
- Always store and pass report ranges as yyyy-MM month strings
- Validate date config when loading saved reports, before building spreadsheets
- Use monthUtils helpers rather than hand-formatting dates
- Add unit tests feeding malformed end dates to report builders
When it happens
Trigger: Calling calendarSpreadsheet with an end date that is not a valid yyyy-MM month string (e.g. '2024-13', 'abc', '', '2024/05') so monthUtils.lastDayOfMonth or d.parse throws inside the try block.
Common situations: A saved report/dashboard has a corrupted or hand-edited start/end month in its config; a custom plugin or API integration passes an arbitrary date string instead of a month string; a locale-related refactor changes the date format passed into report builders.
Related errors
- Invalid date format provided
- Invalid date values provided
- Start date must be before or equal to end date.
- Invalid start date format
- Report recall error
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/7e3f37095ed19abf.
Report an issue: GitHub.