actualbudget/actual · error
File name matches multiple files: ${path}
Error message
File name matches multiple files: ${path} What it means
During YNAB4 import, getFile filters zip entries for an exact path match and throws when two or more entries have the identical name. YNAB4 exports normally contain unique entry names, so this signals a malformed or duplicated archive.
Source
Thrown at packages/loot-core/src/server/importers/ynab4.ts:423
unixFilepath = unixFilepath.replace(/\.zip$/, '').replace(/.ynab4$/, '');
// Most budgets are named like "Budget~51938D82.ynab4" but sometimes
// they are only "Budget.ynab4". We only want to grab the name
// before the ~ if it exists.
const m = unixFilepath.match(/([^/~]+)[^/]*$/);
if (!m) {
return null;
}
return m[1];
}
function getFile(entries: string[], path: string) {
const files = entries.filter(e => e === path);
if (files.length === 0) {
throw new Error('Could not find file: ' + path);
}
if (files.length >= 2) {
throw new Error('File name matches multiple files: ' + path);
}
return files[0];
}
function join(...paths: string[]): string {
return paths.slice(1).reduce(
(full, path) => {
return full + '/' + path.replace(/^\//, '');
},
paths[0].replace(/\/$/, ''),
);
}
export function parseFile(buffer: Buffer): YNAB4.YFull {
let zipped: Record<string, Uint8Array>;
try {
zipped = safeUnzip(buffer);
} catch (e) {View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-export the budget from YNAB4 to get a clean archive with unique entry names.
- Rebuild the zip from an extracted copy so each file appears once.
- Inspect with unzip -l to find the duplicated entries and remove one when re-zipping.
Defensive patterns
Strategy: validation
Validate before calling
function hasDuplicateEntries(buffer) {
const entries = Object.keys(safeUnzip(buffer));
return new Set(entries).size !== entries.length;
} Type guard
function isWellFormedZip(buffer) {
try {
const entries = Object.keys(safeUnzip(buffer));
return entries.length > 0 && new Set(entries).size === entries.length;
} catch { return false; }
} Try / catch
try {
const budget = parseFile(buffer);
} catch (e) {
if (e.message.startsWith('File name matches multiple files')) {
// rebuild the archive from an extracted copy
} else throw e;
} Prevention
- Never concatenate or merge YNAB4 archives.
- Re-zip only from a fully extracted directory so each entry is written once.
- Check archives with unzip -l for duplicated names before import.
- Prefer fresh exports from YNAB4 over repaired/converted archives.
When it happens
Trigger: parseFile(buffer) called on a zip containing two entries with the exact same path string (e.g. duplicate Budget.yfull entries produced by concatenating archives or a buggy zip writer).
Common situations: Merged or re-compressed budget archives; zip files repaired by tools that duplicated entries; archives edited programmatically and re-written with the same entry added twice.
Related errors
- Could not find file: ${path}
- Error reading zip file
- Error reading Budget.yfull file
- zipMeta ? getUnsafeZipError(zipMeta) : error
- Could not find account for transaction when importing
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/9f3ba3e9fc9f7493.
Report an issue: GitHub.