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 = 0View on GitHub (pinned to 81571269ad)
Solutions
- Regenerate the archive from the original source with a correct zipper so names are unique.
- Treat the file as untrusted and reject it; do not attempt to de-duplicate during extraction.
- 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
- Only import archives from your own exporter; reject third-party/user-supplied zips for restore.
- Never attempt to de-duplicate during extraction; treat duplicates as a corrupt/unsafe archive.
- Log the duplicated path so the producer can be fixed.
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
- ZIP archive central directory is invalid
- ZIP entry compression ratio is unsafe: ${entry.name}
- ZIP archive compression ratio is unsafe
- Backup JSON entry is too large: ${path}
- Backup contains too many entries
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/2a6a21b5142723e3.
Report an issue: GitHub.