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.
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
- invalid zip central directory entry
- zip contains no files
- zip does not contain an HTML file
- zip entry exceeds archive
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/0ed8899dfbd374e4.
Report an issue: GitHub.
Appendix: 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)