chatboxai/chatbox · error · Error

Backup uncompressed size exceeds the safety limit

Error message

Backup uncompressed size exceeds the safety limit

What it means

Thrown by enforceArchiveLimits() in the Uint8Array branch when the running total of uncompressed bytes (accumulated across all entries so far) exceeds DEFAULT_ZIP_LIMITS.maxTotalUncompressedBytes (4 GiB). This is the whole-archive uncompressed-size guard, preventing a backup from producing a zip whose decompressed form is unbounded — a zip-bomb defense. It fires after the per-entry check (116) on the same entry.

Source

Thrown at src/renderer/packages/backup/export-backup.ts:118

    archive: { path, data: bytes, compress: true },
    descriptor: { path, size: bytes.length, checksum: await sha256Checksum(bytes) },
  }
}

async function* enforceArchiveLimits(
  entries: AsyncIterable<ZipArchiveEntry>
): AsyncGenerator<ZipArchiveEntry, void, unknown> {
  let entryCount = 0
  let totalUncompressedBytes = 0
  for await (const entry of entries) {
    entryCount++
    if (entryCount > DEFAULT_ZIP_LIMITS.maxEntries) throw new Error('Backup contains too many entries')
    const maxEntryBytes = backupEntryByteLimit(entry.path)
    if (entry.data instanceof Uint8Array) {
      if (entry.data.length > maxEntryBytes) throw new Error(`Backup entry is too large: ${entry.path}`)
      totalUncompressedBytes += entry.data.length
      if (totalUncompressedBytes > DEFAULT_ZIP_LIMITS.maxTotalUncompressedBytes) {
        throw new Error('Backup uncompressed size exceeds the safety limit')
      }
      yield entry
      continue
    }
    let entryBytes = 0
    const data = entry.data
    yield {
      ...entry,
      data: (async function* () {
        for await (const chunk of data) {
          entryBytes += chunk.length
          totalUncompressedBytes += chunk.length
          if (entryBytes > maxEntryBytes) throw new Error(`Backup entry is too large: ${entry.path}`)
          if (totalUncompressedBytes > DEFAULT_ZIP_LIMITS.maxTotalUncompressedBytes) {
            throw new Error('Backup uncompressed size exceeds the safety limit')
          }
          yield chunk
        }

View on GitHub (pinned to 81571269ad)

Solutions

  1. Narrow the export scope (fewer conversations, exclude global resources).
  2. Archive older conversations to a separate backup file so each stays under 4 GiB uncompressed.
  3. Prune large/unused resources from storage before exporting.
  4. If the data is legitimately larger, split the export into multiple backup files by date range.
Defensive patterns

Strategy: validation

Validate before calling

const MAX_TOTAL = 4 * 1024 * 1024 * 1024
function estimateUncompressedSize(sessions: unknown[]): number {
  // sum known blob sizes; rough pre-export check
  return sessions.reduce((acc, s) => acc + estimateSessionBytes(s), 0)
}
if (estimateUncompressedSize(sessions) > MAX_TOTAL) {
  throw new Error('Combined uncompressed size exceeds 4 GiB; narrow the scope')
}

Try / catch

try {
  await exportBackup({ items: ['conversations'] })
} catch (error) {
  if (error instanceof Error && /uncompressed size exceeds/i.test(error.message)) {
    showToast('Backup exceeds the 4 GiB safety limit. Export fewer conversations or resources.')
  } else throw error
}

Prevention

When it happens

Trigger: The sum of all entry.data.length values (for Uint8Array entries seen so far, plus any streaming entries already counted) crosses 4 GiB. With many sessions and resources, the cumulative size triggers this before any single entry hits its own limit. The check runs per-entry as they stream through.

Common situations: A user with a large conversation history and many image/file attachments; accumulated resources over months of use; a backup scope that includes all global resources. The 4 GiB ceiling matches a practical memory/disk budget for the renderer process.

Related errors


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