{"record":{"id":"5ccb06d1e700ccd1","repo":"different-ai/openwork","slug":"workspace-archive-contains-too-much-uncompressed-d","errorCode":null,"errorMessage":"Workspace archive contains too much uncompressed data.","messagePattern":"Workspace archive contains too much uncompressed data\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/workspace-archive.mjs","lineNumber":205,"sourceCode":"function listZipEntries(buffer) {\n  if (buffer.byteLength > MAX_ARCHIVE_BYTES) throw new Error(\"Workspace archive is too large.\");\n  const eocd = findEndOfCentralDirectory(buffer);\n  const count = buffer.readUInt16LE(eocd + 10);\n  if (count > MAX_ARCHIVE_ENTRIES) throw new Error(\"Workspace archive contains too many entries.\");\n  const centralOffset = buffer.readUInt32LE(eocd + 16);\n  const entries = [];\n  let totalUncompressed = 0;\n  let cursor = centralOffset;\n  for (let i = 0; i < count; i += 1) {\n    if (buffer.readUInt32LE(cursor) !== ZIP_CENTRAL_DIRECTORY_HEADER) {\n      throw new Error(\"Invalid ZIP central directory entry.\");\n    }\n    const method = buffer.readUInt16LE(cursor + 10);\n    const compressedSize = buffer.readUInt32LE(cursor + 20);\n    const uncompressedSize = buffer.readUInt32LE(cursor + 24);\n    if (uncompressedSize > MAX_ENTRY_UNCOMPRESSED_BYTES) throw new Error(`Archive entry exceeds the ${MAX_ENTRY_UNCOMPRESSED_BYTES}-byte limit.`);\n    totalUncompressed += uncompressedSize;\n    if (totalUncompressed > MAX_TOTAL_UNCOMPRESSED_BYTES) throw new Error(\"Workspace archive contains too much uncompressed data.\");\n    const nameLength = buffer.readUInt16LE(cursor + 28);\n    const extraLength = buffer.readUInt16LE(cursor + 30);\n    const commentLength = buffer.readUInt16LE(cursor + 32);\n    const localOffset = buffer.readUInt32LE(cursor + 42);\n    const name = buffer.toString(\"utf8\", cursor + 46, cursor + 46 + nameLength);\n    entries.push({ name, method, compressedSize, uncompressedSize, localOffset });\n    cursor += 46 + nameLength + extraLength + commentLength;\n  }\n  return entries;\n}\n\nfunction readZipEntryData(buffer, entry) {\n  if (entry.uncompressedSize > MAX_ENTRY_UNCOMPRESSED_BYTES) throw new Error(`Archive entry exceeds the ${MAX_ENTRY_UNCOMPRESSED_BYTES}-byte limit.`);\n  const cursor = entry.localOffset;\n  if (buffer.readUInt32LE(cursor) !== ZIP_LOCAL_FILE_HEADER) {\n    throw new Error(`Invalid ZIP local header for ${entry.name}.`);\n  }\n  const nameLength = buffer.readUInt16LE(cursor + 26);","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/workspace-archive.mjs#L187-L223","documentation":"listZipEntries sums the declared uncompressedSize of every central-directory entry and enforces a 64 MiB total (MAX_TOTAL_UNCOMPRESSED_BYTES). When the cumulative size exceeds the cap, the whole archive is rejected before any entry is extracted, protecting against zip bombs and decompression blowups.","triggerScenarios":"importWorkspaceConfig on an archive whose combined declared uncompressed sizes across all entries exceed 67108864 bytes (64 MiB), even if each individual entry is under 16 MiB.","commonSituations":"Aggregating many medium config/asset files into one workspace export; an archive accumulated over time with lots of .opencode/ data; crafted archives that pass the per-entry check but exceed total budget.","solutions":["Trim the archive so total uncompressed content stays under 64 MiB","Split the workspace into multiple smaller archives and import selectively","Remove large binaries from .opencode/ and re-export the workspace","Verify with `unzip -l archive.zip` that the summed uncompressed size is under 64 MiB before importing"],"exampleFix":"// before\nunzip -l ws.zip  # total 90000 KB -> throws\n// after\nzip -d ws.zip '.opencode/assets/*'  # total now 21000 KB -> imports","handlingStrategy":"validation","validationCode":"import { execFile } from 'node:child_process';\nfunction totalUncompressedUnder64MiB(zipListingBytes) {\n  return zipListingBytes <= 64 * 1024 * 1024;\n}","typeGuard":"function isWithinTotalLimit(entries) {\n  return Array.isArray(entries) &&\n    entries.reduce((sum, e) => sum + (e.uncompressedSize || 0), 0) <= 64 * 1024 * 1024;\n}","tryCatchPattern":"try {\n  await importWorkspaceConfig({ archivePath, targetDir });\n} catch (err) {\n  if (err.message === 'Workspace archive contains too much uncompressed data.') {\n    // split or trim the archive and retry with a smaller one\n  } else throw err;\n}","preventionTips":["Sum uncompressed sizes with `unzip -l` before importing","Split large workspaces into multiple archives","Exclude generated/asset directories from exports"],"tags":["zip","security","zip-bomb","limit-exceeded"],"backgroundTag":"archive-entry-size-limit","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}