actualbudget/actual · error · APIError
Invalid month format, use YYYY-MM: ${month}
Error message
Invalid month format, use YYYY-MM: ${month} What it means
validateMonth throws APIError when a month argument passed to a public API method does not match the required YYYY-MM format. The API validates all month-typed inputs before executing handlers so budget lookups receive a well-formed month string. This is an input validation guard, not a data problem.
Source
Thrown at packages/loot-core/src/server/api.ts:92
if (connection.getNumClients() > 1) {
connection.send('sync-event', {
type: 'success',
tables: rows.map(row => row.dataset),
});
}
return result;
},
{ undoDisabled: true },
);
};
}
let handlers = {} as unknown as Handlers;
async function validateMonth(month) {
if (!month.match(/^\d{4}-\d{2}$/)) {
throw APIError('Invalid month format, use YYYY-MM: ' + month);
}
if (!IMPORT_MODE) {
const { start, end } = await handlers['get-budget-bounds']();
const range = monthUtils.range(start, end);
if (!range.includes(month)) {
throw APIError('No budget exists for month: ' + month);
}
}
}
async function validateExpenseCategory(debug, id) {
if (id == null) {
throw APIError(`${debug}: category id is required`);
}
const row = await db.first<Pick<db.DbCategory, 'is_income'>>(
'SELECT is_income FROM categories WHERE id = ?',View on GitHub (pinned to d4334cb6e6)
Solutions
- Format the month as a 4-digit year, hyphen, 2-digit zero-padded month (e.g. '2024-01')
- Use a formatter like month.toISOString().slice(0, 7) or date-fns format(date, 'yyyy-MM') to derive the string
- Validate the string with /^\d{4}-\d{2}$/ before calling the API
- If you have a full date, strip the day portion first
Example fix
// before
await q.getBudgetMonth('2024-1'); // APIError: Invalid month format
await q.getBudgetMonth(new Date().toISOString()); // '2024-01-15T...'
// after
await q.getBudgetMonth('2024-01');
await q.getBudgetMonth(new Date().toISOString().slice(0, 7)); Defensive patterns
Strategy: validation
Validate before calling
function isValidMonth(m) {
return typeof m === 'string' && /^\d{4}-\d{2}$/.test(m);
}
if (!isValidMonth(month)) throw new Error(`month must be YYYY-MM, got: ${month}`); Type guard
function isMonth(value) {
return typeof value === 'string' && /^\d{4}-\d{2}$/.test(value);
} Prevention
- Always derive month strings via toISOString().slice(0, 7) or date-fns format(date, 'yyyy-MM')
- Never pass full ISO datetimes to month parameters
- Zero-pad single-digit months
- Add a regex assertion on month inputs in your own API wrapper
When it happens
Trigger: Calling API methods that take a month (e.g. getBudgetMonth, setBudgetAmount, getCategories) with strings like '2024', '2024-1', '2024/01', '2024-01-01', or an empty string.
Common situations: Passing a full ISO date ('2024-01-15') instead of a month; building the month string with JS Date without zero-padding; forgetting month is 1-indexed in some libraries (month '1' not '01'); passing undefined coerced to a string.
Related errors
- Unknown payee name normalization: ${String(normalization)}
- `date` is required when adding a transaction
- Amount is invalid, must be an integer: ${trans.amount}
- There is already a filter named ${item.name}
- Filter name is required
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/0834168bbe9fd724.
Report an issue: GitHub.