actualbudget/actual · error
File not found at the provided path: ${filepath}
Error message
File not found at the provided path: ${filepath} What it means
`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.
Source
Thrown at packages/loot-core/src/server/budgetfiles/app.ts:490
type,
}: {
type: ImportableBudgetType;
/** Path to the file to import, on the engine's filesystem. */
filepath?: string;
/** Raw contents of the file to import; alternative to `filepath`. */
buffer?: ArrayBuffer;
/**
* Original name of the imported file; only used together with `buffer`,
* to derive the budget name for some import types.
*/
filename?: string;
}): Promise<{ error?: string; meta?: unknown; id?: string }> {
try {
let contents: Buffer;
let name: string;
if (filepath != null) {
if (!(await fs.exists(filepath))) {
throw new Error(`File not found at the provided path: ${filepath}`);
}
contents = Buffer.from(await fs.readFile(filepath, 'binary'));
name = filepath;
} else if (buffer != null) {
contents = Buffer.from(buffer);
name = filename || 'budget-import';
} else {
throw new Error('Either `filepath` or `buffer` must be given');
}
const results = await handleBudgetImport(type, name, contents);
if (results && results.error) {
return results;
}
// A successful import leaves the imported budget loaded
return { id: prefs.getPrefs()?.id };
} catch (err) {View on GitHub (pinned to d4334cb6e6)
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.
Example fix
// before
await importBudget({ type: 'ynab4', filepath: '~/exports/budget.yfull' });
// after
import path from 'path';
import os from 'os';
import fs from 'fs/promises';
const filepath = path.resolve('~/exports/budget.yfull'.replace(/^~/, os.homedir()));
await fs.access(filepath); // throws early if missing
await importBudget({ type: 'ynab4', filepath }); Defensive patterns
Strategy: validation
Validate before calling
import fs from 'fs/promises';
import path from 'path';
import os from 'os';
async function assertImportFileExists(filepath) {
const abs = path.resolve(String(filepath).replace(/^~/, os.homedir()));
const stat = await fs.stat(abs); // throws ENOENT early with the real path
if (!stat.isFile()) throw new Error(`Not a file: ${abs}`);
return abs;
} Type guard
async function isReadableFile(filepath) {
try {
return (await fs.stat(filepath)).isFile();
} catch {
return false;
}
} Try / catch
try {
await importBudget({ type, filepath });
} catch (e) {
if (e.message.startsWith('File not found')) {
console.error(`Check the path: ${e.message} (cwd=${process.cwd()})`);
} else {
throw e;
}
} Prevention
- 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)
When it happens
Trigger: 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).
Common situations: 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.
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
- File not found at the provided path: ${filePath}
- Could not find file: ${path}
- Error reading Budget.yfull file
- Error importing budget: ${result.error}
- Error importing budget: no budget was loaded
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/1fd6feda892cbeb6.
Report an issue: GitHub.