{"record":{"id":"fd1a51372f50d9de","repo":"chatboxai/chatbox","slug":"backup-manifest-statistics-do-not-match-its-entrie","errorCode":null,"errorMessage":"Backup manifest statistics do not match its entries","messagePattern":"Backup manifest statistics do not match its entries","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/renderer/packages/backup/types.ts","lineNumber":151,"sourceCode":"      if (!resourcesById.get(resourceId)?.sessionIds.includes(session.id)) {\n        throw new Error(`Session/resource mapping is inconsistent: ${session.id}/${resourceId}`)\n      }\n    }\n  }\n  for (const resource of manifest.resources) {\n    for (const sessionId of resource.sessionIds) {\n      const session = sessionsById.get(sessionId)\n      if (!session?.resourceIds.includes(resource.id)) {\n        throw new Error(`Resource/session mapping is inconsistent: ${resource.id}/${sessionId}`)\n      }\n    }\n  }\n  if (\n    manifest.stats.sessionCount !== manifest.sessions.length ||\n    manifest.stats.resourceCount !== manifest.resources.length ||\n    manifest.stats.warningCount !== manifest.warnings.length\n  ) {\n    throw new Error('Backup manifest statistics do not match its entries')\n  }\n}\n\nexport interface BackupProgress {\n  phase: 'preparing' | 'sessions' | 'resources' | 'packing' | 'reading' | 'validating' | 'restoring'\n  current: number\n  total: number\n  label?: string\n}\n\nexport interface BackupStorage {\n  getAllKeys(): Promise<string[]>\n  getItem<T>(key: string, initialValue: T): Promise<T>\n  setItemNow<T>(key: string, value: T): Promise<void>\n  removeItem(key: string): Promise<void>\n  getBlob(key: string): Promise<string | null>\n  setBlob(key: string, value: string): Promise<void>\n  delBlob(key: string): Promise<void>","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/backup/types.ts#L133-L169","documentation":"Thrown when the manifest's declared stats counts disagree with the actual array lengths: sessionCount must equal sessions.length, resourceCount must equal resources.length, and warningCount must equal warnings.length. Note that deduplicatedResourceCount is intentionally NOT checked here.","triggerScenarios":"manifest.stats.sessionCount / resourceCount / warningCount differs from the corresponding array length.","commonSituations":"Stats computed before entries were finalized; a hand-edit that added/removed an entry without updating stats; an exporter off-by-one.","solutions":["Recompute stats from the arrays right before packing the manifest.","Set sessionCount = sessions.length, resourceCount = resources.length, warningCount = warnings.length.","Re-export."],"exampleFix":"// before\nvalidateBackupManifestGraph(manifest)\n\n// after\nmanifest.stats = {\n  ...manifest.stats,\n  sessionCount: manifest.sessions.length,\n  resourceCount: manifest.resources.length,\n  warningCount: manifest.warnings.length,\n}","handlingStrategy":"validation","validationCode":"function statsMatchEntries(manifest: BackupManifest): boolean {\n  return (\n    manifest.stats.sessionCount === manifest.sessions.length &&\n    manifest.stats.resourceCount === manifest.resources.length &&\n    manifest.stats.warningCount === manifest.warnings.length\n  )\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateBackupManifestGraph(manifest)\n} catch (error) {\n  if (/statistics do not match/.test((error as Error).message)) recomputeStats(manifest)\n  throw error\n}","preventionTips":["Compute stats last, after all entry arrays are finalized.","Derive counts from array length, never from a running counter.","Remember deduplicatedResourceCount is not checked by this guard."],"tags":["backup","manifest","validation","stats"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}