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
- Recreate the file by re-uploading/importing the budget or re-running the code path that writes it first
- Verify the exact path string (trailing slashes, remote vs local prefix) matches what was written
- 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
- Always call fs.exists (or wrap reads in try/catch) before reading persisted paths
- Remember browser storage can be cleared — never assume local files persist across sessions
- Keep budget data synced to the server so local loss is recoverable
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
- getModifiedTime not supported on the web (only used for back
- ACTUAL_DATA_DIR env variable is required
- Failed to copy SQL file from ${frompath} to ${topath}: ${sec
- indexeddb-quota-error
- File not found at the provided path: ${filepath}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/58093c936d11054f.
Report an issue: GitHub.