actualbudget/actual · error · Error
Error reading Budget.yfull file
Error message
Error reading Budget.yfull file
What it means
After locating Budget.yfull inside the zip, parseFile converts the entry bytes to a UTF-8 string inside a try/catch and throws this error if reading fails — typically because getFile (290/291) or the buffer conversion failed, so the underlying cause is usually a missing/misplaced entry rather than an I/O problem.
Source
Thrown at packages/loot-core/src/server/importers/ynab4.ts:470
const metaStr = Buffer.from(zipped[getFile(entries, root + 'Budget.ymeta')]);
const meta = JSON.parse(metaStr.toString('utf8'));
const budgetPath = join(root, meta.relativeDataFolderName);
const deviceFiles = entries.filter(e =>
e.startsWith(join(budgetPath, 'devices')),
);
const deviceGUID = findLatestDevice(zipped, deviceFiles);
const yfullPath = join(budgetPath, deviceGUID, 'Budget.yfull');
let contents;
try {
contents = Buffer.from(zipped[getFile(entries, yfullPath)]).toString(
'utf8',
);
} catch (e) {
logger.log(e);
throw new Error('Error reading Budget.yfull file');
}
try {
return JSON.parse(contents);
} catch {
throw new Error('Error parsing Budget.yfull file');
}
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Check the import logs for the wrapped original error (e.g. 'Could not find file: ...') — fix the zip layout so Budget.yfull is at the expected path.
- Re-export the budget from YNAB4 with the default folder structure and retry.
- Confirm the archive actually contains Budget.yfull at its root folder (unzip -l).
- If the file is present but binary-corrupted, restore from another backup.
Defensive patterns
Strategy: validation
Validate before calling
function zipContainsYfull(buffer) {
const entries = Object.keys(safeUnzip(buffer));
return entries.some(e => e.endsWith('Budget.yfull')) &&
entries.find(e => e.endsWith('Budget.yfull')).length > 0;
} Type guard
function isYnab4Layout(entries) {
return Array.isArray(entries) &&
entries.some(e => /[^/]*\.ynab4\//.test(e)) &&
entries.some(e => e.endsWith('Budget.yfull'));
} Try / catch
try {
const budget = parseFile(buffer);
} catch (e) {
if (e.message === 'Error reading Budget.yfull file') {
// check logs for the wrapped cause (missing entry); fix zip layout
} else throw e;
} Prevention
- Confirm Budget.yfull exists at the archive's root *.ynab4 folder before import.
- Read the logger output for the underlying error — this message hides the real cause.
- Restore missing files from another backup rather than hand-building zips.
- Avoid renaming folders inside the export.
When it happens
Trigger: parseFile(buffer) where the Budget.yfull entry lookup throws (wrong path/case, duplicate entries) or the zipped entry is absent/undefined so Buffer.from fails to produce readable UTF-8 content.
Common situations: Re-zipped archives with renamed inner directories; partial uploads missing Budget.yfull; importing an archive whose root folder pattern /([^/]*\.ynab4)/ does not match so the computed path is wrong.
Related errors
- Could not find file: ${path}
- File name matches multiple files: ${path}
- Error reading zip file
- zipMeta ? getUnsafeZipError(zipMeta) : error
- File not found at the provided path: ${filepath}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/989e60f8b7490c2e.
Report an issue: GitHub.