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

  1. Reduce the archive's uncompressed size (e.g. delete and re-export the budget so sqlite is vacuumed).
  2. Import a fresh export of the budget rather than an old bloated zip.
  3. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/d22396ad770e1ca2. Report an issue: GitHub.