chatboxai/chatbox · error

ZIP contains too many entries

Error message

ZIP contains too many entries

What it means

Thrown after incrementing entryCount when it exceeds limits.maxEntries (default 100,004 from DEFAULT_ZIP_LIMITS). It is a zip-bomb / resource-exhaustion guard that aborts streaming before the archive can enumerate an attacker-controlled or pathologically large number of entries.

Source

Thrown at src/renderer/packages/backup/zip.ts:227

  onEntry: (entry: ReadZipEntry) => Promise<void> | void,
  options: ZipReadOptions = {}
): Promise<void> {
  await validateZipEndOfCentralDirectory(file)
  const limits = { ...DEFAULT_ZIP_LIMITS, ...options.limits }
  const seenPaths = new Set<string>()
  const pendingHandlers: Promise<void>[] = []
  let entryCount = 0
  let totalUncompressedBytes = 0
  let fatalError: unknown

  const unzip = new Unzip((entry) => {
    try {
      throwIfAborted(options.signal)
      assertSafeArchivePath(entry.name)
      if (seenPaths.has(entry.name)) throw new Error(`Duplicate ZIP entry: ${entry.name}`)
      seenPaths.add(entry.name)
      entryCount++
      if (entryCount > limits.maxEntries) throw new Error('ZIP contains too many entries')
      const entryLimits = { ...limits, ...options.entryLimits?.(entry.name) }
      if (entry.originalSize !== undefined && entry.originalSize > entryLimits.maxEntryUncompressedBytes) {
        throw new Error(`ZIP entry is too large: ${entry.name}`)
      }
      if (
        entry.size !== undefined &&
        entry.originalSize !== undefined &&
        entry.originalSize > 1024 * 1024 &&
        entry.originalSize > Math.max(1, entry.size) * entryLimits.maxCompressionRatio
      ) {
        throw new Error(`ZIP entry compression ratio is unsafe: ${entry.name}`)
      }

      const chunks: Uint8Array[] = []
      let entryBytes = 0
      entry.ondata = (error, data, final) => {
        if (fatalError) return
        if (error) {

View on GitHub (pinned to 81571269ad)

Solutions

  1. Pass a higher limits.maxEntries in ZipReadOptions if the archive is trusted and known large.
  2. Re-export the backup excluding unnecessary tiny files to shrink the entry count.
  3. Keep the default cap for untrusted imports and surface a clear 'too many files' message to the user.

Example fix

// before
await readZipFileEntries(file, onEntry)

// after: raise the cap for trusted full backups
await readZipFileEntries(file, onEntry, {
  limits: { maxEntries: 500_000 }
})
Defensive patterns

Strategy: validation

Validate before calling

// Configure the cap to match the trusted archive's known entry count.
const options: ZipReadOptions = {
  limits: { maxEntries: 500_000 }, // raise for trusted full backups
}
await readZipFileEntries(file, onEntry, options)

Try / catch

try {
  await readZipFileEntries(file, onEntry, { limits: { maxEntries } })
} catch (error) {
  if (error instanceof Error && error.message === 'ZIP contains too many entries') {
    // Either raise the cap (trusted) or reject (untrusted).
  } else throw error
}

Prevention

When it happens

Trigger: An archive with more than 100,004 entries, or with more than a caller-lowered maxEntries. Trips as soon as the (entryCount+1)-th entry callback fires.

Common situations: Legitimate large backups (e.g. node_modules or many small chat-attachment files) that breach the default, hostile test archives, or an integration that set limits.maxEntries too low.

Related errors


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/3f7717a29cdac016. Report an issue: GitHub.