actualbudget/actual · error · UnsafeZipError
Zip entry "${file.name}" exceeds maximum size of ${maxEntryS
Error message
Zip entry "${file.name}" exceeds maximum size of ${maxEntrySize} bytes What it means
During unzipSync's filter callback, each entry's uncompressed size (originalSize) is checked against maxEntrySize before extraction. Any single entry exceeding the limit throws UnsafeZipError with zipReason 'entry-size', naming the entry and the limit. This prevents one huge file inside the archive from exhausting memory.
Source
Thrown at packages/loot-core/src/server/util/zip.ts:67
}: SafeUnzipOptions = {},
): Unzipped {
if (data.length > maxArchiveSize) {
throw new UnsafeZipError(
`Zip archive exceeds maximum size of ${maxArchiveSize} bytes`,
{ zipReason: 'archive-size', maxSize: maxArchiveSize },
);
}
const seen = new Set<string>();
let totalUncompressedSize = 0;
return unzipSync(data, {
filter(file) {
assertSafeEntryName(file.name);
if (file.originalSize > maxEntrySize) {
throw new UnsafeZipError(
`Zip entry "${file.name}" exceeds maximum size of ${maxEntrySize} bytes`,
{
zipReason: 'entry-size',
entryName: file.name,
maxSize: maxEntrySize,
},
);
}
totalUncompressedSize += file.originalSize;
if (totalUncompressedSize > maxTotalUncompressedSize) {
throw new UnsafeZipError(
`Zip archive's total uncompressed size exceeds maximum of ${maxTotalUncompressedSize} bytes`,
{ zipReason: 'total-size', maxSize: maxTotalUncompressedSize },
);
}
const normalized = file.name.toLowerCase();View on GitHub (pinned to d4334cb6e6)
Solutions
- Inspect the named entry — if it is unexpected, treat the archive as malicious and reject it.
- For legitimate large entries, raise maxEntrySize when calling safeUnzip.
- Check entry sizes from the central directory before extraction in your own pre-scan and report a friendly error.
- Never bypass the check on untrusted archives; process oversized entries in a worker with a hard memory cap instead.
Example fix
// before
const entries = safeUnzip(buffer);
// after
const entries = safeUnzip(buffer, {
maxEntrySize: 200 * 1024 * 1024, // allow bigger individual files
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Read central directory sizes before extraction if available, or cap input:
if (buf.length > MAX_ARCHIVE) throw new Error('Archive too large to inspect safely'); Try / catch
try {
const entries = safeUnzip(buf);
} catch (e) {
if (e instanceof UnsafeZipError && e.zipReason === 'entry-size') {
showError(`Entry "${e.entryName}" is too large (limit ${e.maxSize} bytes)`);
} else { throw e; }
} Prevention
- Treat small-zip-huge-content ratios as a bomb indicator and reject
- Configure maxEntrySize explicitly for workloads with legitimately large files
- Run extraction of untrusted archives in a memory-capped worker
When it happens
Trigger: A zip containing one entry whose decompressed size exceeds maxEntrySize (default MAX_ZIP_SIZE) — a decompression bomb with a small compressed payload expanding to gigabytes, or a legitimately huge single export file.
Common situations: Malicious archives designed to expand massively on extraction; backups containing very large embedded attachments; importing third-party archives of unknown content.
Related errors
- Zip archive's total uncompressed size exceeds maximum of ${m
- Zip archive exceeds maximum size of ${maxArchiveSize} bytes
- zip-too-large
- 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/ed086ee3b0bc4e12.
Report an issue: GitHub.