{"record":{"id":"566be18369ce0188","repo":"chatboxai/chatbox","slug":"backup-contains-too-many-entries","errorCode":null,"errorMessage":"Backup contains too many entries","messagePattern":"Backup contains too many entries","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/packages/backup/export-backup.ts","lineNumber":112,"sourceCode":"  path: string,\n  value: unknown\n): Promise<{ archive: ZipArchiveEntry; descriptor: BackupJsonEntry }> {\n  const bytes = new TextEncoder().encode(JSON.stringify(value))\n  if (bytes.length > MAX_BACKUP_JSON_ENTRY_BYTES) throw new Error(`Backup JSON entry is too large: ${path}`)\n  return {\n    archive: { path, data: bytes, compress: true },\n    descriptor: { path, size: bytes.length, checksum: await sha256Checksum(bytes) },\n  }\n}\n\nasync function* enforceArchiveLimits(\n  entries: AsyncIterable<ZipArchiveEntry>\n): AsyncGenerator<ZipArchiveEntry, void, unknown> {\n  let entryCount = 0\n  let totalUncompressedBytes = 0\n  for await (const entry of entries) {\n    entryCount++\n    if (entryCount > DEFAULT_ZIP_LIMITS.maxEntries) throw new Error('Backup contains too many entries')\n    const maxEntryBytes = backupEntryByteLimit(entry.path)\n    if (entry.data instanceof Uint8Array) {\n      if (entry.data.length > maxEntryBytes) throw new Error(`Backup entry is too large: ${entry.path}`)\n      totalUncompressedBytes += entry.data.length\n      if (totalUncompressedBytes > DEFAULT_ZIP_LIMITS.maxTotalUncompressedBytes) {\n        throw new Error('Backup uncompressed size exceeds the safety limit')\n      }\n      yield entry\n      continue\n    }\n    let entryBytes = 0\n    const data = entry.data\n    yield {\n      ...entry,\n      data: (async function* () {\n        for await (const chunk of data) {\n          entryBytes += chunk.length\n          totalUncompressedBytes += chunk.length","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/backup/export-backup.ts#L94-L130","documentation":"Thrown by enforceArchiveLimits() when the number of zip entries exceeds DEFAULT_ZIP_LIMITS.maxEntries (100,004). This is the zip-bomb / unbounded-growth guard at the archive level — it counts every entry (JSON and resource) and aborts before the zip writer consumes excessive file handles or metadata. The check fires on the entry-count branch before per-entry size is evaluated.","triggerScenarios":"A backup export produces more than 100,004 archive members. Each session contributes one JSON entry plus N resource entries (images, files), so a very large session count or a session with many attachments can exceed the cap. The check runs as entries stream through enforceArchiveLimits.","commonSituations":"User has tens of thousands of conversations with attachments; a corrupted store produced duplicate entries; resources were not deduplicated so each message embeds its own copy. The 100,004 ceiling matches the zip format's 16-bit entry limit headroom (65535 for classic zip) with a safety margin for the writer used.","solutions":["Export a subset of conversations rather than the entire history.","Deduplicate resources (the backup already has resource-candidate logic — verify it is applied) so identical files are stored once.","Archive older conversations into separate backup files so each stays under the entry cap."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const MAX_ENTRIES = 100_004\nfunction estimateEntryCount(sessions: unknown[], resourcesPerSession: number): number {\n  return sessions.length + sessions.length * resourcesPerSession\n}\nif (estimateEntryCount(sessions, avgResources) > MAX_ENTRIES) {\n  throw new Error('Too many entries for a single backup; narrow the scope')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await exportBackup({ items: ['conversations'] })\n} catch (error) {\n  if (error instanceof Error && /too many entries/i.test(error.message)) {\n    showToast('Backup is too large. Export fewer conversations.')\n  } else throw error\n}","preventionTips":["Narrow the export scope instead of backing up everything at once.","Ensure resources are deduplicated so identical files count once.","Archive older conversations into separate backup files."],"tags":["backup","export","size-limit","zip","archive"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}