{"record":{"id":"58093c936d11054f","repo":"actualbudget/actual","slug":"file-does-not-exist-filepath","errorCode":null,"errorMessage":"File does not exist: ${filepath}","messagePattern":"File does not exist: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/platform/server/fs/index.ts","lineNumber":133,"sourceCode":"): Promise<string>;\nasync function _readFile(\n  filepath: string,\n  opts?: { encoding: 'binary' },\n): Promise<Uint8Array>;\nasync function _readFile(\n  filepath: string,\n  opts?: { encoding: 'utf8' } | { encoding: 'binary' },\n): Promise<string | Uint8Array> {\n  // We persist stuff in /documents, but don't need to handle sqlite\n  // file specifically because those are symlinked to a separate\n  // filesystem and will be handled in the BlockedFS\n  if (\n    !NO_PERSIST &&\n    isPersistedPath(filepath) &&\n    !filepath.endsWith('.sqlite')\n  ) {\n    if (!_exists(filepath)) {\n      throw new Error('File does not exist: ' + filepath);\n    }\n\n    // Grab contents from IDB\n    const { store } = idb.getStore(await idb.getDatabase(), 'files');\n    const item = await idb.get(store, filepath);\n\n    if (item == null) {\n      throw new Error('File does not exist: ' + filepath);\n    }\n\n    if (opts?.encoding === 'utf8' && ArrayBuffer.isView(item.contents)) {\n      return String.fromCharCode.apply(\n        null,\n        new Uint16Array(item.contents.buffer),\n      );\n    }\n\n    return item.contents;","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/platform/server/fs/index.ts#L115-L151","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { exists } from './platform/server/fs';\nif (!(await exists(filepath))) {\n  throw new Error(`Skipping read; file was never written: ${filepath}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const data = await fs.readFile(filepath);\n} catch (e) {\n  if (String(e).startsWith('File does not exist')) {\n    // recreate via the writer path or restore from backup/sync\n  } else throw e;\n}","preventionTips":["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"],"tags":["fs","indexeddb","file-not-found","web"],"backgroundTag":"file-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}