{"record":{"id":"8eec30b809b5532c","repo":"nexu-io/open-design","slug":"invalid-zip-local-header-entry-name","errorCode":null,"errorMessage":"invalid zip local header: ${entry.name}","messagePattern":"invalid zip local header: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/daemon/src/design/claude-design-import.ts","lineNumber":235,"sourceCode":"      isDirectory: name.endsWith('/'),\n    });\n    offset += 46 + nameLen + extraLen + commentLen;\n  }\n  return entries;\n}\n\nfunction findEndOfCentralDirectory(zip: Buffer): number {\n  const min = Math.max(0, zip.length - 0xffff - 22);\n  for (let i = zip.length - 22; i >= min; i -= 1) {\n    if (zip.readUInt32LE(i) === EOCD_SIG) return i;\n  }\n  throw new Error('invalid zip: missing central directory');\n}\n\nfunction readEntryBody(zip: Buffer, entry: ZipEntry): Buffer {\n  const offset = entry.localOffset;\n  if (zip.readUInt32LE(offset) !== LOCAL_SIG) {\n    throw new Error(`invalid zip local header: ${entry.name}`);\n  }\n  const nameLen = zip.readUInt16LE(offset + 26);\n  const extraLen = zip.readUInt16LE(offset + 28);\n  const bodyStart = offset + 30 + nameLen + extraLen;\n  const bodyEnd = bodyStart + entry.compressedSize;\n  if (bodyEnd > zip.length) throw new Error(`zip entry exceeds archive: ${entry.name}`);\n  const compressed = zip.slice(bodyStart, bodyEnd);\n  if (entry.method === 0) return Buffer.from(compressed);\n  // A genuinely empty deflate payload would still occupy at least the BFINAL\n  // marker; an entirely missing payload cannot be inflated, so treat it as\n  // empty rather than handing a zero-length buffer to zlib.\n  if (compressed.length === 0) return Buffer.alloc(0);\n  // When the central directory advertises 0 (streaming zips with data\n  // descriptors), fall back to the per-file ceiling so legitimate non-empty\n  // payloads decode instead of being silently truncated. The post-decode\n  // checks in the caller enforce MAX_FILE_BYTES and total-bytes limits.\n  const cap = entry.uncompressedSize > 0 ? entry.uncompressedSize : MAX_FILE_BYTES;\n  return inflateRawSync(compressed, { maxOutputLength: cap });","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/design/claude-design-import.ts#L217-L253","documentation":"For each entry, readEntryBody reads the local file header at entry.localOffset (taken from the central directory). The first 4 bytes must be the local file header signature 0x04034b50 (LOCAL_SIG). A mismatch means the central directory's local-header offset is wrong or the local region is corrupt. Maps to HTTP 400.","triggerScenarios":"A zip where the central directory points at offsets that don't hold local headers — typically from a packager that wrote inconsistent offsets, a zip edited after creation, or bytes prepended (e.g. a self-extracting stub) that shifted local headers without adjusting offsets.","commonSituations":"Self-extracting archives with a prepended stub; zips modified by tools that rewrite the central directory without fixing offsets; archives repaired by 'zip -FF' that left offset drift.","solutions":["Re-export fresh from Claude Design.","Re-zip with a standard conformant tool (Info-ZIP, Finder, Windows Explorer).","Avoid self-extracting wrappers; upload a plain deflate zip."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Local-header/offset drift isn't cheap to detect without a full parser;\n// rely on `unzip -t` as the pre-flight.\nimport { execFileSync } from 'node:child_process';\nfunction zipPassesTest(file: string): boolean {\n  try { execFileSync('unzip', ['-tqq', file], { stdio: 'ignore' }); return true; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await importClaudeDesignZip(zipPath, projectDir);\n} catch (err) {\n  if (String(err).includes('invalid zip local header')) {\n    return res.status(400).json({ error: 'zip has inconsistent local headers; re-create it' });\n  }\n  throw err;\n}","preventionTips":["Avoid self-extracting archives (prepended stubs shift offsets).","Do not repair zips with `zip -FF` and then import; re-create cleanly.","Run `unzip -t` before upload to catch offset drift."],"tags":["zip","parsing","local-header","import","claude-design"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}