nexu-io/open-design · error · Error
invalid zip central directory
Error message
invalid zip central directory
What it means
Thrown by `readCentralDirectory` when the end-of-central-directory record's `centralOffset + centralSize` exceeds the actual archive buffer length. The central directory points past the end of the file, so the archive is truncated or corrupt and cannot be safely parsed.
Source
Thrown at apps/daemon/src/design/claude-design-import.ts:189
// trackpad. Ignore those here; explicit zoom is Cmd+wheel or the host
// toolbar.
let isGesturing = false;
const onGestureStart = (e) => { e.preventDefault(); e.stopPropagation(); isGesturing = true; };
const onGestureChange = (e) => {
e.preventDefault();
e.stopPropagation();
};
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');View on GitHub (pinned to 5be4028344)
Solutions
- Re-obtain the zip from the original source to rule out truncation during transfer.
- Verify integrity with a standard unzip tool; if it fails to list contents, the archive is corrupt.
- If you produce the archive, ensure the writer flushes the full file and writes a consistent EOCD.
Defensive patterns
Strategy: validation
Validate before calling
const eocdOffset = findEndOfCentralDirectory(zip);
const centralSize = zip.readUInt32LE(eocdOffset + 12);
const centralOffset = zip.readUInt32LE(eocdOffset + 16);
if (centralOffset + centralSize > zip.length) {
throw new Error('archive central directory extends past end of file; archive is truncated');
} Try / catch
try {
await importClaudeDesignZip(zipPath, projectDir);
} catch (err) {
if (err instanceof Error && err.message === 'invalid zip central directory') {
// re-obtain the archive; it is truncated or corrupt
}
throw err;
} Prevention
- Re-obtain archives from the original source to rule out truncation during transfer.
- Verify archive integrity with a standard unzip tool before importing.
- Ensure the zip writer flushes the full file and writes a consistent EOCD.
When it happens
Trigger: A zip whose EOCD record advertises a central directory offset/size that extends beyond the file bytes held in memory — e.g. a partially downloaded archive, a truncated file, or a corrupt/truncated central directory.
Common situations: The zip was truncated during download or transfer. Disk write was interrupted. A buggy producer wrote an inconsistent EOCD. An attacker crafted a misleading EOCD.
Related errors
- zip entry size mismatch: ${relPath}
- zip contains no files
- zip does not contain an HTML file
- invalid zip central directory entry
- zip entry exceeds archive: ${entry.name}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/0ed8899dfbd374e4.
Report an issue: GitHub.