{"record":{"id":"1fd6feda892cbeb6","repo":"actualbudget/actual","slug":"file-not-found-at-the-provided-path-filepath","errorCode":null,"errorMessage":"File not found at the provided path: ${filepath}","messagePattern":"File not found at the provided path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budgetfiles/app.ts","lineNumber":490,"sourceCode":"  type,\n}: {\n  type: ImportableBudgetType;\n  /** Path to the file to import, on the engine's filesystem. */\n  filepath?: string;\n  /** Raw contents of the file to import; alternative to `filepath`. */\n  buffer?: ArrayBuffer;\n  /**\n   * Original name of the imported file; only used together with `buffer`,\n   * to derive the budget name for some import types.\n   */\n  filename?: string;\n}): Promise<{ error?: string; meta?: unknown; id?: string }> {\n  try {\n    let contents: Buffer;\n    let name: string;\n    if (filepath != null) {\n      if (!(await fs.exists(filepath))) {\n        throw new Error(`File not found at the provided path: ${filepath}`);\n      }\n\n      contents = Buffer.from(await fs.readFile(filepath, 'binary'));\n      name = filepath;\n    } else if (buffer != null) {\n      contents = Buffer.from(buffer);\n      name = filename || 'budget-import';\n    } else {\n      throw new Error('Either `filepath` or `buffer` must be given');\n    }\n\n    const results = await handleBudgetImport(type, name, contents);\n    if (results && results.error) {\n      return results;\n    }\n    // A successful import leaves the imported budget loaded\n    return { id: prefs.getPrefs()?.id };\n  } catch (err) {","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budgetfiles/app.ts#L472-L508","documentation":"`importBudget` accepts either a `filepath` or an in-memory `buffer` of a budget file to import. When a `filepath` is supplied, the function checks `fs.exists(filepath)` first and throws this error if the file cannot be found, before any parsing happens. It exists to give a clear, path-including message instead of a downstream read/parse failure.","triggerScenarios":"Calling `importBudget({ type, filepath, ... })` where the path does not exist: a typo in the filename, a relative path resolved against the wrong working directory, the file was deleted/moved before the call, or a path from another machine (e.g. a browser-side path passed to a Node-side API, where it never resolves on the server).","commonSituations":"Automation scripts using `~/file.yclf` without shell expansion (tilde is not expanded by Node); importing a CSV/YNAB export in a container where the file was not volume-mounted; a UI passing a fake path from a file picker's security-layer name; running the import from a different cwd than expected.","solutions":["Check the file exists at the exact path using `fs.existsSync` / `fs/promises.stat` before calling `importBudget`, and confirm the path printed in the error.","Expand `~` and convert relative paths to absolute with `path.resolve` — Node does not expand `~` and resolves relative to `process.cwd()`.","In desktop/server contexts, remember only server-accessible paths work; pass a `buffer` instead of a `filepath` if the file lives on the client.","Fix volume mounts/container paths so the file is visible to the process running Actual."],"exampleFix":"// before\nawait importBudget({ type: 'ynab4', filepath: '~/exports/budget.yfull' });\n\n// after\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs/promises';\nconst filepath = path.resolve('~/exports/budget.yfull'.replace(/^~/, os.homedir()));\nawait fs.access(filepath); // throws early if missing\nawait importBudget({ type: 'ynab4', filepath });","handlingStrategy":"validation","validationCode":"import fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\n\nasync function assertImportFileExists(filepath) {\n  const abs = path.resolve(String(filepath).replace(/^~/, os.homedir()));\n  const stat = await fs.stat(abs);          // throws ENOENT early with the real path\n  if (!stat.isFile()) throw new Error(`Not a file: ${abs}`);\n  return abs;\n}","typeGuard":"async function isReadableFile(filepath) {\n  try {\n    return (await fs.stat(filepath)).isFile();\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  await importBudget({ type, filepath });\n} catch (e) {\n  if (e.message.startsWith('File not found')) {\n    console.error(`Check the path: ${e.message} (cwd=${process.cwd()})`);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Resolve ~ and relative paths with path.resolve + os.homedir before calling","Verify the file is visible inside the container/volume the server process runs in","For client-originated files, send a buffer instead of a client-side path","Confirm the file still exists between listing it and importing it (TOCTOU in watched folders)"],"tags":["filesystem","import","file-not-found"],"backgroundTag":"file-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}