nexu-io/open-design · error · Error

encrypted zip entries are not supported

Error message

encrypted zip entries are not supported

What it means

The general-purpose bit-flag's bit 0 (read from offset+8 at line 198) marks the entry as encrypted. The importer supports only unencrypted stored (method 0) and deflate (method 8) entries, so any encrypted entry aborts the import. Maps to HTTP 400 via the /api/import/claude-design route.

Source

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

    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,
      uncompressedSize,
      localOffset,
      isDirectory: name.endsWith('/'),
    });
    offset += 46 + nameLen + extraLen + commentLen;
  }
  return entries;
}

function findEndOfCentralDirectory(zip: Buffer): number {
  const min = Math.max(0, zip.length - 0xffff - 22);

View on GitHub (pinned to 5be4028344)

Solutions

  1. Re-export the Claude Design project without encryption.
  2. Unzip the protected archive locally (supplying the password) and re-zip the result with no password.
  3. Disable encryption in the archiving tool and recreate the zip.

Example fix

// before: archive created with encryption
//   zip --password secret export.zip design-canvas.jsx
// after: plain deflate archive
//   zip export.zip design-canvas.jsx
Defensive patterns

Strategy: validation

Validate before calling

// Detect encryption by reading general-purpose bit flag bit 0 of each
// central-directory entry before importing.
import { openSync, readSync } from 'node:fs';
function zipHasEncryptedEntries(file: string): boolean {
  // Cheap heuristic: `unzip -l` annotates encrypted entries; fall back to
  // a dedicated zip reader (yauzl) for a precise per-entry check.
  try {
    const out = execFileSync('unzip', ['-l', file], { encoding: 'utf8' });
    return /Encrypted|~/.test(out); // unzip marks encrypted entries
  } catch {
    return false;
  }
}

Try / catch

try {
  await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
  if (String(err).includes('encrypted')) {
    return res.status(400).json({ error: 'encrypted zips are not supported' });
  }
  throw err;
}

Prevention

When it happens

Trigger: Uploading a password-protected or AES/ZipCrypto-encrypted zip to POST /api/import/claude-design; readCentralDirectory parses each entry and (flags & 1) !== 0 fails on the first encrypted entry.

Common situations: The user re-archived an export with encryption enabled; corporate archiving defaults that apply encryption; a shared/protected zip; macOS 'Encrypt' option or 7-Zip AES.

Related errors


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