actualbudget/actual · error · Error

File does not exist: ${filepath}

Error message

File does not exist: ${filepath}

What it means

The web (IDB-backed) `fs` implementation checks `_exists()` before reading a persisted, non-sqlite file from IndexedDB. If the file isn't present on disk (in-memory fs) it throws immediately, before even consulting IDB.

Source

Thrown at packages/loot-core/src/platform/server/fs/index.ts:133

): Promise<string>;
async function _readFile(
  filepath: string,
  opts?: { encoding: 'binary' },
): Promise<Uint8Array>;
async function _readFile(
  filepath: string,
  opts?: { encoding: 'utf8' } | { encoding: 'binary' },
): Promise<string | Uint8Array> {
  // We persist stuff in /documents, but don't need to handle sqlite
  // file specifically because those are symlinked to a separate
  // filesystem and will be handled in the BlockedFS
  if (
    !NO_PERSIST &&
    isPersistedPath(filepath) &&
    !filepath.endsWith('.sqlite')
  ) {
    if (!_exists(filepath)) {
      throw new Error('File does not exist: ' + filepath);
    }

    // Grab contents from IDB
    const { store } = idb.getStore(await idb.getDatabase(), 'files');
    const item = await idb.get(store, filepath);

    if (item == null) {
      throw new Error('File does not exist: ' + filepath);
    }

    if (opts?.encoding === 'utf8' && ArrayBuffer.isView(item.contents)) {
      return String.fromCharCode.apply(
        null,
        new Uint16Array(item.contents.buffer),
      );
    }

    return item.contents;

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Recreate the file by re-uploading/importing the budget or re-running the code path that writes it first
  2. Verify the exact path string (trailing slashes, remote vs local prefix) matches what was written
  3. If data was cleared, restore from a backup or the sync server instead of reading locally
Defensive patterns

Strategy: try-catch

Validate before calling

import { exists } from './platform/server/fs';
if (!(await exists(filepath))) {
  throw new Error(`Skipping read; file was never written: ${filepath}`);
}

Try / catch

try {
  const data = await fs.readFile(filepath);
} catch (e) {
  if (String(e).startsWith('File does not exist')) {
    // recreate via the writer path or restore from backup/sync
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `readFile`/`contents` on a persisted path (tracked by `isPersistedPath`, e.g. budget metadata files) that was never written in this browser profile, or whose record was evicted/cleared while the in-memory check also fails.

Common situations: A different browser profile or cleared IndexedDB losing files the app expects; a race where a file was deleted between the exists check and read; hand-crafted paths pointing at files that don't exist.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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