different-ai/openwork · error
Invalid ZIP local header for ${entry.name}.
Error message
Invalid ZIP local header for ${entry.name}. What it means
readZipEntryData validates the local file header signature (0x04034b50) at the entry's localOffset before reading entry data. If the bytes there are not the local header magic, the archive is corrupt, the offsets are wrong, or the file is not actually a ZIP, so extraction aborts with the entry name in the message.
Source
Thrown at apps/desktop/electron/workspace-archive.mjs:221
if (uncompressedSize > MAX_ENTRY_UNCOMPRESSED_BYTES) throw new Error(`Archive entry exceeds the ${MAX_ENTRY_UNCOMPRESSED_BYTES}-byte limit.`);
totalUncompressed += uncompressedSize;
if (totalUncompressed > MAX_TOTAL_UNCOMPRESSED_BYTES) throw new Error("Workspace archive contains too much uncompressed data.");
const nameLength = buffer.readUInt16LE(cursor + 28);
const extraLength = buffer.readUInt16LE(cursor + 30);
const commentLength = buffer.readUInt16LE(cursor + 32);
const localOffset = buffer.readUInt32LE(cursor + 42);
const name = buffer.toString("utf8", cursor + 46, cursor + 46 + nameLength);
entries.push({ name, method, compressedSize, uncompressedSize, localOffset });
cursor += 46 + nameLength + extraLength + commentLength;
}
return entries;
}
function readZipEntryData(buffer, entry) {
if (entry.uncompressedSize > MAX_ENTRY_UNCOMPRESSED_BYTES) throw new Error(`Archive entry exceeds the ${MAX_ENTRY_UNCOMPRESSED_BYTES}-byte limit.`);
const cursor = entry.localOffset;
if (buffer.readUInt32LE(cursor) !== ZIP_LOCAL_FILE_HEADER) {
throw new Error(`Invalid ZIP local header for ${entry.name}.`);
}
const nameLength = buffer.readUInt16LE(cursor + 26);
const extraLength = buffer.readUInt16LE(cursor + 28);
const dataStart = cursor + 30 + nameLength + extraLength;
const compressed = buffer.subarray(dataStart, dataStart + entry.compressedSize);
if (entry.method === 0) return compressed;
if (entry.method === 8) {
return zlib.inflateRawSync(compressed, {
finishFlush: zlib.constants.Z_SYNC_FLUSH,
maxOutputLength: MAX_ENTRY_UNCOMPRESSED_BYTES,
});
}
throw new Error(`Unsupported ZIP compression method ${entry.method} for ${entry.name}.`);
}
function isSafeArchivePath(name) {
if (!name || name.startsWith("/") || /^[A-Za-z]:/.test(name)) return false;
const normalized = normalizeZipPath(name);View on GitHub (pinned to 2b7df46e8a)
Solutions
- Re-download/re-transfer or re-export the archive; the file is likely truncated or corrupt
- Verify the file with `unzip -t archive.zip` or `file archive.zip` before importing
- Ensure the source really is a ZIP produced by exportWorkspaceConfig, not a renamed file
- Do not manually patch offsets; regenerate the archive from a working copy
Example fix
// before
importWorkspaceConfig({ archivePath: './notes.json.zip' }) // actually JSON
// after
file notes.json.zip # confirm 'Zip archive data'
importWorkspaceConfig({ archivePath: './workspace-export.zip' }) Defensive patterns
Strategy: validation
Validate before calling
import { readFile } from 'node:fs/promises';
async function looksLikeZip(filePath) {
const buf = await readFile(filePath);
return buf.length > 4 && buf.readUInt32LE(0) === 0x04034b50;
} Type guard
function hasZipMagic(buf) {
return buf.length >= 4 && buf.readUInt32LE(0) === 0x04034b50;
} Try / catch
try {
await importWorkspaceConfig({ archivePath, targetDir });
} catch (err) {
if (String(err.message).startsWith('Invalid ZIP local header')) {
// corrupt/truncated/non-zip file: re-export or re-download
} else throw err;
} Prevention
- Run `unzip -t archive.zip` before importing
- Avoid renaming non-zip files to .zip
- Re-export the archive if a transfer was interrupted
When it happens
Trigger: importWorkspaceConfig on a truncated, concatenated, or non-ZIP file that still passed a partial central-directory scan; an archive whose central directory offsets point at garbage; a renamed non-zip file given as archivePath.
Common situations: Partial upload/download of the archive file, a .zip produced by a tool writing data descriptors (streaming zip) with offset mismatches, or a user passing a text/JSON file renamed to .zip.
Related errors
- ZIP central directory entry is out of bounds.
- ZIP entry ${name} uses unsupported compression method ${meth
- ZIP data for ${entry.name} is out of bounds.
- ZIP uncompressed size mismatch for ${entry.name}.
- XLSX workbook.xml was not found.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/7e6b8694ca260557.
Report an issue: GitHub.