chatboxai/chatbox · error

Duplicate ZIP entry: ${entry.name}

Error message

Duplicate ZIP entry: ${entry.name}

What it means

Thrown inside the Unzip per-entry callback when an entry.name has already been added to the seenPaths Set. Duplicate entry names are treated as a defect because extraction logic that writes by path would silently overwrite or merge, a common path-collision attack vector against archive extractors.

Source

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

export async function readZipFileEntries(
  file: File,
  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

View on GitHub (pinned to 81571269ad)

Solutions

  1. Regenerate the archive from the original source with a correct zipper so names are unique.
  2. Treat the file as untrusted and reject it; do not attempt to de-duplicate during extraction.
  3. Audit the producer to confirm whether directory entries are double-counted with file entries.
Defensive patterns

Strategy: try-catch

Validate before calling

// Duplicate detection is streaming; a full pre-scan is costly. The library
// already enforces uniqueness. Pre-validate only the trusted-source contract:
function isTrustedArchiveSource(source: string): boolean {
  return source === 'chatbox-backup-export' // only accept your own exporter
}

Try / catch

try {
  await readZipFileEntries(file, onEntry, { signal })
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Duplicate ZIP entry')) {
    reportToUser('The archive contains duplicate files and was rejected for safety.')
  } else {
    throw error
  }
}

Prevention

When it happens

Trigger: A zip deliberately crafted with two entries sharing the same name (zip-merge/overwrite attacks), archives produced by buggy mergers that duplicated entries, or zips that list a directory entry and a file entry with identical names.

Common situations: Importing a third-party or user-supplied backup, merging two archives with a naive zipper, or processing an archive generated by an exporter that emits redundant directory markers.

Related errors


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