nexu-io/open-design · error · Error

zip contains no files

Error message

zip contains no files

What it means

Thrown by `importClaudeDesignZip` after the entry loop completes if no decodable file entries were collected (`files.length === 0`). This happens when the archive contains only directory entries, or has no entries at all. There is nothing to import, so the importer fails fast rather than producing an empty project.

Source

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

    // 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;
  };

  await mkdir(projectDir, { recursive: true });
  await Promise.all(files.map(async (f) => {
    const target = safeJoin(projectDir, f.path);
    await ensureDir(path.dirname(target));
    await writeFile(target, f.body);

View on GitHub (pinned to 5be4028344)

Solutions

  1. Re-create the archive ensuring it contains at least one real file entry.
  2. Verify the source export actually produced files; re-export if necessary.
  3. Check that the zip tool did not store files as directory-only entries.
Defensive patterns

Strategy: validation

Validate before calling

const fileEntries = entries.filter((e) => !e.isDirectory);
if (fileEntries.length === 0) {
  throw new Error('archive contains no file entries');
}

Try / catch

try {
  await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
  if (err instanceof Error && err.message === 'zip contains no files') {
    // re-create the archive with at least one real file
  }
  throw err;
}

Prevention

When it happens

Trigger: Uploading an empty zip. Uploading a zip that contains only directory entries (all entries end with `/`). An archive whose entries were all filtered out as directories.

Common situations: An empty or placeholder archive. A zip created by accidentally zipping a folder's structure without its files. A tool that emitted directory entries but skipped file payloads.

Related errors


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