nexu-io/open-design · error · Error

invalid zip central directory entry

Error message

invalid zip central directory entry

What it means

Thrown by readCentralDirectory while walking the declared number of central-directory entries. Each entry must begin with the central-directory file-header signature 0x02014b50 (CENTRAL_SIG). If the 4 bytes at the current offset don't match, the central directory is corrupt, truncated, or the walking offset has desynchronized because a prior entry's nameLen/extraLen/commentLen fields were wrong. The HTTP route POST /api/import/claude-design maps this to 400.

Source

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

    };
    const onGestureEnd = (e) => { e.preventDefault(); e.stopPropagation(); isGesturing = false; };`);
  return { result, wheelMatched, gestureMatched };
}

function readCentralDirectory(zip: Buffer): ZipEntry[] {
  const eocdOffset = findEndOfCentralDirectory(zip);
  const entryCount = zip.readUInt16LE(eocdOffset + 10);
  const centralSize = zip.readUInt32LE(eocdOffset + 12);
  const centralOffset = zip.readUInt32LE(eocdOffset + 16);
  if (centralOffset + centralSize > zip.length) {
    throw new Error('invalid zip central directory');
  }

  const entries: ZipEntry[] = [];
  let offset = centralOffset;
  for (let i = 0; i < entryCount; i += 1) {
    if (zip.readUInt32LE(offset) !== CENTRAL_SIG) {
      throw new Error('invalid zip central directory entry');
    }
    const flags = zip.readUInt16LE(offset + 8);
    const method = zip.readUInt16LE(offset + 10);
    const compressedSize = zip.readUInt32LE(offset + 20);
    const uncompressedSize = zip.readUInt32LE(offset + 24);
    const nameLen = zip.readUInt16LE(offset + 28);
    const extraLen = zip.readUInt16LE(offset + 30);
    const commentLen = zip.readUInt16LE(offset + 32);
    const localOffset = zip.readUInt32LE(offset + 42);
    const name = zip.slice(offset + 46, offset + 46 + nameLen).toString('utf8');
    if ((flags & 1) !== 0) throw new Error('encrypted zip entries are not supported');
    if (method !== 0 && method !== 8) {
      throw new Error(`unsupported zip compression method: ${method}`);
    }
    entries.push({
      name,
      method,
      compressedSize,

View on GitHub (pinned to 5be4028344)

Solutions

  1. Re-export the Claude Design project to a fresh zip and retry the upload.
  2. Verify the archive opens in a standard unzip tool (e.g. `unzip -t file.zip`) before uploading.
  3. Confirm the multipart upload completed fully (compare uploaded size to source size).
  4. If the zip is generated programmatically, validate central-directory consistency with a conformant zip library before sending.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight the archive with a conformant unzip before importing.
import { execFileSync } from 'node:child_process';
function zipIsSound(file: string): boolean {
  try {
    execFileSync('unzip', ['-tqq', file], { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}
if (!zipIsSound(uploadPath)) return res.status(400).json({ error: 'corrupt zip' });

Try / catch

// importClaudeDesignZip throws a plain Error; catch at the route/caller.
try {
  const imported = await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
  // All zip-structure errors surface here; the HTTP route returns 400.
  return res.status(400).json({ error: String(err) });
}

Prevention

When it happens

Trigger: Calling importClaudeDesignZip (or uploading a multipart 'file' to POST /api/import/claude-design) on a zip whose central directory is malformed: a truncated archive, an entry whose declared name/extra/comment lengths push the next offset into invalid data, or a central directory that was copied from a different archive.

Common situations: A file renamed to .zip that isn't a real archive; a partially downloaded/uploaded zip; a zip produced by a non-conformant packager; corruption introduced by a proxy/CDN truncating the multipart upload; a zip edited after creation.

Related errors


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