different-ai/openwork · error
Archive entry exceeds the
Error message
Archive entry exceeds the ${MAX_ENTRY_UNCOMPRESSED_BYTES}-byte limit. What it means
listZipEntries parses the ZIP central directory when reading a workspace archive. It enforces a per-entry uncompressed-size cap (MAX_ENTRY_UNCOMPRESSED_BYTES = 16 MiB, read from the central directory header at offset +24). If any single entry declares an uncompressed size above that limit, parsing is aborted with this error to prevent zip bombs and memory exhaustion before any data is inflated.
Solutions
- Remove or exclude the oversized entry from the archive so every entry is under 16 MiB uncompressed
- Re-export the workspace after moving large data files out of .opencode/ and opencode.json scope
- If the file is legitimately needed, compress it into a smaller artifact or store it outside the workspace config
- If the archive came from an untrusted source, treat it as hostile — do not attempt to inflate it
Example fix
// before: archive contains .opencode/model.bin (40 MB uncompressed) // after: exclude it or store externally .opencode/ agent.md plugin.js # model.bin moved to external storage, archive now imports cleanly
Defensive patterns
Strategy: validation
Validate before calling
import { stat } from 'node:fs/promises';
// pre-check total and rough sizes: use `unzip -l` or a zip parser before import
// e.g. with yauzl/fflate: ensure every entry.uncompressedSize <= 16 * 1024 * 1024 Type guard
function isWithinEntryLimit(entry) {
return typeof entry?.uncompressedSize === 'number' &&
entry.uncompressedSize >= 0 &&
entry.uncompressedSize <= 16 * 1024 * 1024;
} Try / catch
try {
await importWorkspaceConfig({ archivePath, targetDir });
} catch (err) {
if (String(err.message).includes('-byte limit')) {
// archive entry too large: reject or ask user to trim the archive
} else throw err;
} Prevention
- Keep .opencode/ free of large binaries and datasets
- Run `unzip -l` to check per-entry uncompressed sizes before importing
- Treat untrusted archives as hostile — the limit also guards zip bombs
When it happens
Trigger: Calling importWorkspaceConfig (or listZipEntries directly) on an archive where at least one central-directory entry has an uncompressedSize field greater than 16777216 bytes.
Common situations: Importing a workspace archive exported from a project with very large files under .opencode/ (e.g. bundled assets, databases, video), or a hand-crafted/malicious zip bomb with a small compressed size but huge declared uncompressed size.
Related errors
- Workspace archive contains too much uncompressed data.
- Office XML exceeds the parser input limit.
- ZIP central directory entry is out of bounds.
- ZIP entry uses unsupported compression method .
- a request body cannot be redirected to another origin
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/e91292bb3927cc32.
Report an issue: GitHub.
Appendix: source
Thrown at apps/desktop/electron/workspace-archive.mjs:203
}
function listZipEntries(buffer) {
if (buffer.byteLength > MAX_ARCHIVE_BYTES) throw new Error("Workspace archive is too large.");
const eocd = findEndOfCentralDirectory(buffer);
const count = buffer.readUInt16LE(eocd + 10);
if (count > MAX_ARCHIVE_ENTRIES) throw new Error("Workspace archive contains too many entries.");
const centralOffset = buffer.readUInt32LE(eocd + 16);
const entries = [];
let totalUncompressed = 0;
let cursor = centralOffset;
for (let i = 0; i < count; i += 1) {
if (buffer.readUInt32LE(cursor) !== ZIP_CENTRAL_DIRECTORY_HEADER) {
throw new Error("Invalid ZIP central directory entry.");
}
const method = buffer.readUInt16LE(cursor + 10);
const compressedSize = buffer.readUInt32LE(cursor + 20);
const uncompressedSize = buffer.readUInt32LE(cursor + 24);
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}.`);View on GitHub (pinned to 2b7df46e8a)