actualbudget/actual · critical · Error
Document directory is not set
Error message
Document directory is not set
What it means
Actual's server filesystem layer stores the user's chosen document (budget data) directory in a module-level `documentDir` variable, set via `_setDocumentDir`. `getDocumentDir` throws this error when any code tries to resolve a file path before that directory has been configured. It signals a lifecycle bug: filesystem APIs were used before app initialization set the root directory.
Source
Thrown at packages/loot-core/src/platform/server/fs/shared.ts:9
// @ts-strict-ignore
import { join } from '#platform/server/fs/path-join';
let documentDir;
export const _setDocumentDir = dir => (documentDir = dir);
export const getDocumentDir = () => {
if (!documentDir) {
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(View on GitHub (pinned to d4334cb6e6)
Solutions
- Ensure `_setDocumentDir(dir)` (or the app's init/bootstrap that calls it) runs before any filesystem or budget-path call.
- If writing a custom script/test, call `_setDocumentDir` explicitly with a writable temp/app directory at setup.
- Check for code that resets or clears documentDir mid-session and re-set it after that point.
Example fix
// before
import { getBudgetDir } from './shared';
const dir = getBudgetDir(budgetId);
// after
import { _setDocumentDir, getBudgetDir } from './shared';
_setDocumentDir('/home/user/.actual');
const dir = getBudgetDir(budgetId); Defensive patterns
Strategy: validation
Validate before calling
import { _setDocumentDir } from './shared';
// at bootstrap, before any fs call:
if (!process.env.ACTUAL_DOCUMENT_DIR) {
throw new Error('Set the document directory before initializing Actual');
}
_setDocumentDir(process.env.ACTUAL_DOCUMENT_DIR); Prevention
- Always run the app bootstrap/init sequence before touching budget-path APIs.
- In tests, set the document dir in a shared beforeEach/setup fixture.
- Never clear documentDir without immediately re-setting it.
When it happens
Trigger: Calling any fs/path helper that resolves through getDocumentDir (e.g. getBudgetDir) before `_setDocumentDir(dir)` has been invoked during app/budget initialization; resetting the module state in tests and forgetting to re-set the dir; importing server fs code into a context that never runs the init sequence.
Common situations: Running loot-core server code in a script or test harness that skipped the normal bootstrap; calling budget-loading APIs early in Electron/renderer startup; a code path that cleared documentDir (e.g. after closing a budget) but still resolves paths.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- getDocumentDir: id is falsy: ${id}
- error
- Failed to create sheet
- Invalid budget id "${id}". Check the id of your budget in th
- Failed to duplicate budget file: ${error.message}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/e2ff69a8a76f5e41.
Report an issue: GitHub.