nexu-io/open-design · error · Error

zip is too large

Error message

zip is too large

What it means

Thrown by `importClaudeDesignZip` when the running cumulative total of decoded entry body lengths exceeds `MAX_TOTAL_BYTES` (100 MiB). This is the aggregate zip-bomb guard, evaluated after each entry is decoded and added to the running total.

Source

Thrown at apps/daemon/src/design/claude-design-import.ts:51

    if (files.length >= MAX_FILES) throw new Error('zip contains too many files');
    const relPath = sanitizeZipPath(entry.name);
    if (entry.uncompressedSize > MAX_FILE_BYTES) {
      throw new Error(`zip file too large: ${relPath}`);
    }

    // Decode first; the central directory's uncompressedSize is unreliable for
    // streaming/data-descriptor zips (it can read 0 even when the payload
    // carries real data). The inflate cap and the post-decode size checks below
    // are authoritative.
    const body = readEntryBody(zip, entry);
    if (body.length > MAX_FILE_BYTES) {
      throw new Error(`zip file too large: ${relPath}`);
    }
    if (entry.uncompressedSize > 0 && body.length !== entry.uncompressedSize) {
      throw new Error(`zip entry size mismatch: ${relPath}`);
    }
    totalBytes += body.length;
    if (totalBytes > MAX_TOTAL_BYTES) throw new Error('zip is too large');

    files.push({ path: relPath, body: normalizeImportedClaudeDesignFile(relPath, body) });
  }

  if (files.length === 0) throw new Error('zip contains no files');
  const entryFile = chooseEntryFile(files.map((f) => f.path));
  if (!entryFile) throw new Error('zip does not contain an HTML file');

  const dirCreates = new Map<string, Promise<string | undefined>>();
  const ensureDir = (dir: string) => {
    let pending = dirCreates.get(dir);
    if (!pending) {
      pending = mkdir(dir, { recursive: true });
      dirCreates.set(dir, pending);
    }
    return pending;
  };

View on GitHub (pinned to 5be4028344)

Solutions

  1. Trim the archive contents so the total decoded size is at or below 100 MiB.
  2. Exclude bulky directories and externalize large media.
  3. Re-export selecting only the HTML and essential assets.
Defensive patterns

Strategy: validation

Validate before calling

const MAX_TOTAL_BYTES = 100 * 1024 * 1024;
let total = 0;
for (const entry of entries.filter((e) => !e.isDirectory)) {
  total += readEntryBody(zip, entry).length;
  if (total > MAX_TOTAL_BYTES) {
    throw new Error(`archive total ${total} exceeds 100 MiB cap`);
  }
}

Try / catch

try {
  await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
  if (err instanceof Error && err.message === 'zip is too large') {
    // trim aggregate archive size below 100 MiB and re-upload
  }
  throw err;
}

Prevention

When it happens

Trigger: An archive whose combined decoded entries exceed 100 MiB — e.g. many medium-sized files, or a few files that individually pass the 25 MiB per-file cap but together exceed the total.

Common situations: A legitimate but large export bundling many assets. An archive that includes bulky directories (`node_modules`, `dist`, media libraries). A zip bomb designed to pass per-file checks but blow the aggregate budget.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/cd3c956a4b7f9fdb. Report an issue: GitHub.