actualbudget/actual · error
Start date must be before or equal to end date.
Error message
Start date must be before or equal to end date.
What it means
summarySpreadsheet enforces a chronological range: after validating both dates it checks d.isAfter(startDay, endDay) and throws 'Start date must be before or equal to end date.' when the range is inverted. This prevents nonsensical queries (negative or zero-length ranges where the query's $gte bound exceeds $lte) and division issues in per-month/per-year calculations.
Source
Thrown at packages/desktop-client/src/components/reports/spreadsheets/summary-spreadsheet.ts:70
endDay = d.parse(
monthUtils.getMonth(end) ===
monthUtils.getMonth(monthUtils.currentDay())
? monthUtils.currentDay()
: monthUtils.lastDayOfMonth(end),
'yyyy-MM-dd',
new Date(),
);
} catch (error) {
console.error('Error parsing dates:', error);
throw new Error('Invalid date format provided');
}
if (!d.isValid(startDay) || !d.isValid(endDay)) {
throw new Error('Invalid date values provided');
}
if (d.isAfter(startDay, endDay)) {
throw new Error('Start date must be before or equal to end date.');
}
const getOneDatePerMonth = (start: Date, end: Date) => {
const months = [];
let currentDate = d.startOfMonth(start);
while (!d.isSameMonth(currentDate, end)) {
months.push(currentDate);
currentDate = d.addMonths(currentDate, 1);
}
months.push(end);
return months;
};
const makeRootQuery = () =>
q('transactions')
.filter({View on GitHub (pinned to d4334cb6e6)
Solutions
- Swap the arguments so start <= end at the call site
- Validate the ordering before calling: if (new Date(start) > new Date(end)) fix or reject
- Clamp/normalize the range in UI code (e.g. date picker constraints) so an inverted range can't be produced
- Catch the error and show a user-facing message asking to correct the range
Example fix
// before
summarySpreadsheet('2024-06', '2024-01', ...); // inverted
// after
const [start, end] = ['2024-06', '2024-01'].sort(); // or fix the picker constraint
summarySpreadsheet(start, end, ...); Defensive patterns
Strategy: validation
Validate before calling
if (new Date(start + '-01') > new Date(end + '-01')) {
[start, end] = [end, start]; // or reject
} Type guard
function isOrderedRange(start: string, end: string): boolean {
return start <= end; // yyyy-MM compares lexicographically
} Try / catch
try {
await summarySpreadsheet(start, end, conditions, op, content, locale)(spreadsheet, setData);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Start date must be')) {
showUserMessage('Please fix the report date range: start is after end.');
} else throw e;
} Prevention
- Constrain date-range pickers so end can't precede start
- Normalize (sort) start/end before invoking report builders
- Assert ordering in tests for every report component
- Keep start/end as a single {start,end} range object with an invariant check
When it happens
Trigger: Calling summarySpreadsheet with start later than end, e.g. start='2024-06', end='2024-01'; also equal-month ranges where end resolves to a day before start's first day (edge cases with currentDay substitution).
Common situations: Swapped start/end arguments at a call site; a date-range picker letting users set an 'end' before 'start'; programmatic range math (subtracting months from start) that overshoots below end.
Related errors
- Invalid end date format
- Invalid date format provided
- Invalid date values provided
- Invalid start date format
- Report recall error
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/6d06420baafa66af.
Report an issue: GitHub.