actualbudget/actual · error · FileDownloadError
zip-too-large
zip-too-large
Error message
zip-too-large
What it means
importBuffer unzips downloaded/imported budget files using safeUnzip, which enforces size limits to prevent zip bombs. When safeUnzip raises UnsafeZipError (archive too large), importBuffer rethrows a FileDownloadError with code 'zip-too-large' plus metadata.
Source
Thrown at packages/loot-core/src/server/cloud-storage.ts:218
const availableMemory = memory.getAvailableMemory();
if (
availableMemory != null &&
entries['db.sqlite'].length > availableMemory
) {
warnings.push('may-exceed-available-memory');
}
return { data: Buffer.from(zipped), warnings };
}
export async function importBuffer(fileData, buffer) {
let entries;
try {
entries = safeUnzip(buffer);
} catch (e) {
if (e instanceof UnsafeZipError) {
throw FileDownloadError('zip-too-large', e.meta);
}
throw FileDownloadError('not-zip-file');
}
const entryNames = Object.keys(entries);
const dbDirs = entryNames
.filter(name => name === 'db.sqlite' || name.endsWith('/db.sqlite'))
.map(name => name.slice(0, -'db.sqlite'.length));
const metaDirs = entryNames
.filter(name => name === 'metadata.json' || name.endsWith('/metadata.json'))
.map(name => name.slice(0, -'metadata.json'.length));
// Both files must come from the same directory: prefer the archive root,
// otherwise there must be exactly one directory containing both.
const sharedDirs = dbDirs.filter(dir => metaDirs.includes(dir));
const dir = sharedDirs.includes('')
? ''
: sharedDirs.length === 1
? sharedDirs[0]View on GitHub (pinned to d4334cb6e6)
Solutions
- Reduce the archive's uncompressed size (e.g. delete and re-export the budget so sqlite is vacuumed).
- Import a fresh export of the budget rather than an old bloated zip.
- Check e.meta on the error for the size limits involved and confirm the file isn't truncated (re-download).
Defensive patterns
Strategy: try-catch
Validate before calling
const fs = require('fs');
const stat = fs.statSync(zipPath);
if (stat.size > 100 * 1024 * 1024) throw new Error('Archive suspiciously large'); Try / catch
try {
await actual.importActual(zipPath);
} catch (e) {
if (e.code === 'zip-too-large') {
console.error('Archive too large:', e.meta);
} else throw e;
} Prevention
- Re-export fresh budgets instead of importing old bloated zips
- Check archive size before import
- Treat huge zips from unknown sources as suspicious
When it happens
Trigger: Importing a budget file (download from cloud storage or importActual of a .zip export) whose uncompressed contents exceed the safe size limit — oversized db.sqlite inside the zip, or a malicious/accidental zip bomb.
Common situations: Very old, bloated budgets with large unused sqlite pages; importing a corrupted/renamed archive; test fixtures with inflated zips; hosting limits truncating archives.
Related errors
- Zip archive exceeds maximum size of ${maxArchiveSize} bytes
- Zip entry "${file.name}" exceeds maximum size of ${maxEntryS
- Zip archive's total uncompressed size exceeds maximum of ${m
- Unsafe zip entry name: ${name}
- Zip archive contains a duplicate entry: ${file.name}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/d22396ad770e1ca2.
Report an issue: GitHub.