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

  1. Ensure `_setDocumentDir(dir)` (or the app's init/bootstrap that calls it) runs before any filesystem or budget-path call.
  2. If writing a custom script/test, call `_setDocumentDir` explicitly with a writable temp/app directory at setup.
  3. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/e2ff69a8a76f5e41. Report an issue: GitHub.