actualbudget/actual · error · UnsafeZipError
Zip archive exceeds maximum size of ${maxArchiveSize} bytes
Error message
Zip archive exceeds maximum size of ${maxArchiveSize} bytes What it means
safeUnzip enforces a maximum compressed archive size before decompressing to prevent decompression-bomb / resource-exhaustion attacks. If the raw buffer exceeds maxArchiveSize (default MAX_ZIP_SIZE), it throws UnsafeZipError with zipReason 'archive-size' and the configured limit.
Source
Thrown at packages/loot-core/src/server/util/zip.ts:52
}
}
type SafeUnzipOptions = {
maxArchiveSize?: number;
maxEntrySize?: number;
maxTotalUncompressedSize?: number;
};
export function safeUnzip(
data: Uint8Array,
{
maxArchiveSize = MAX_ZIP_SIZE,
maxEntrySize = MAX_ZIP_SIZE,
maxTotalUncompressedSize = MAX_ZIP_SIZE,
}: 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',View on GitHub (pinned to d4334cb6e6)
Solutions
- Check the file size client-side before upload/import and reject archives over the limit early with a clear message.
- If legitimate larger backups are expected, pass a higher maxArchiveSize option to safeUnzip.
- Enforce an HTTP request body limit at the server/proxy layer so oversized uploads fail fast.
- Split or prune the backup (remove attachments) to reduce archive size.
Example fix
// before
const entries = safeUnzip(buffer); // default 25MB-ish limit
// after
const MAX = 100 * 1024 * 1024;
if (buffer.length > MAX) {
throw new Error(`Backup too large (${buffer.length} bytes); limit is ${MAX}`);
}
const entries = safeUnzip(buffer, { maxArchiveSize: MAX }); Defensive patterns
Strategy: validation
Validate before calling
const MAX_ARCHIVE = 25 * 1024 * 1024;
if (data.length > MAX_ARCHIVE) {
throw new Error(`Archive is ${(data.length / 1e6).toFixed(1)}MB; limit is ${MAX_ARCHIVE / 1e6}MB`);
} Try / catch
try {
const entries = safeUnzip(buf);
} catch (e) {
if (e instanceof UnsafeZipError && e.zipReason === 'archive-size') {
showError(`Backup too large — limit is ${e.maxSize} bytes`);
} else { throw e; }
} Prevention
- Check file size before upload/import and fail fast with a clear message
- Enforce an HTTP body-size limit at the proxy/server layer
- Raise maxArchiveSize explicitly if legitimate backups are known to be larger
When it happens
Trigger: Importing or loading a backup zip larger than the configured limit — a legitimately huge budget backup, or an intentionally oversized malicious upload. Callers include loadBackup, importBuffer, and parseFile.
Common situations: Users importing very large backup archives containing many attachments; a server receiving oversized uploads without an HTTP-level body size limit; misconfigured smaller maxArchiveSize rejecting valid archives.
Related errors
- Zip entry "${file.name}" exceeds maximum size of ${maxEntryS
- Zip archive's total uncompressed size exceeds maximum of ${m
- 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/a48bb8b13e84e3b0.
Report an issue: GitHub.