actualbudget/actual · error · Error
Invalid budget id "${id}". Check the id of your budget in th
Error message
Invalid budget id "${id}". Check the id of your budget in the Advanced section of the settings page. What it means
Budget ids become a directory name under the document dir, so getBudgetDir sanitizes them: any character outside [A-Za-z0-9-_] (slashes, dots, spaces, unicode) is rejected to prevent path traversal outside the budget directory. The error tells the user to verify the budget id configured in the Advanced settings section.
Source
Thrown at packages/loot-core/src/platform/server/fs/shared.ts:27
throw new Error('Document directory is not set');
}
return documentDir;
};
export const getBudgetDir = id => {
if (!id) {
throw new Error('getDocumentDir: id is falsy: ' + id);
}
// TODO: This should be better
//
// A cheesy safe guard. The id is generated from the budget name,
// so it provides an entry point for the user to accidentally (or
// intentionally) access other parts of the system. Always
// restrict it to only access files within the budget directory by
// never allowing slashes.
if (id.match(/[^A-Za-z0-9\-_]/)) {
throw new Error(
`Invalid budget id "${id}". Check the id of your budget in the Advanced section of the settings page.`,
);
}
return join(getDocumentDir(), id);
};
View on GitHub (pinned to d4334cb6e6)
Solutions
- Open Settings > Advanced, check the budget id, and correct it to contain only letters, digits, dashes, or underscores.
- Sanitize/validate ids on input: reject or transform anything not matching /^[A-Za-z0-9-_]+$/.
- If an id was derived from a budget name, slugify it (strip or replace disallowed characters) before use.
Example fix
// before
const id = budgetName; // e.g. 'My Budget/2024'
const dir = getBudgetDir(id);
// after
const id = budgetName.replace(/[^A-Za-z0-9\-_]/g, '-');
if (!/^[A-Za-z0-9\-_]+$/.test(id)) {
throw new Error('Budget id must be alphanumeric, dash, or underscore');
}
const dir = getBudgetDir(id); Defensive patterns
Strategy: validation
Validate before calling
const SAFE_ID = /^[A-Za-z0-9\-_]+$/;
if (!SAFE_ID.test(budgetId)) {
throw new Error(`Budget id "${budgetId}" contains invalid characters`);
} Type guard
function isValidBudgetId(id: string): boolean {
return /^[A-Za-z0-9\-_]+$/.test(id);
} Try / catch
try {
const dir = getBudgetDir(id);
} catch (e) {
if (String(e.message).startsWith('Invalid budget id')) {
// surface settings-page guidance to the user
} else throw e;
} Prevention
- Slugify ids derived from names before persisting them.
- Never accept budget ids from unvalidated user input or URLs.
- Document the allowed charset ([A-Za-z0-9-_]) wherever ids are configured.
When it happens
Trigger: Passing a budget id containing '/', '\', '..', whitespace, or other special characters to getBudgetDir; a hand-edited budget id in config/settings; constructing ids from user input without sanitization.
Common situations: A user pasted an incorrect or corrupted id into the Advanced > budget id setting; a self-hosted setup script generated an id from a budget name containing slashes; automated tooling injected URL-encoded or path-like ids.
Related errors
- Unsafe zip entry name: ${name}
- Invalid font-family value for "${property}": function calls
- Invalid font src: only data: URIs are allowed in @font-face.
- Theme CSS contains forbidden at-rules (@import, @media, @key
- getDocumentDir: id is falsy: ${id}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f5192987e19af70f.
Report an issue: GitHub.