chatboxai/chatbox · error · Error
Backup manifest entry list is incomplete
Error message
Backup manifest entry list is incomplete
What it means
Thrown as a final invariant in validateManifestEntries when the number of expected paths does not equal the number of staged entries. The preceding loops already reject duplicate descriptor paths (125), missing staged entries (126), and unexpected staged paths (128), so a size mismatch here indicates an internal logic error rather than bad archive data. Propagates after rollback.
Source
Thrown at src/renderer/packages/backup/import-backup.ts:102
manifest.data.sessionSettings,
...manifest.sessions,
...manifest.resources,
].filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))
const expectedPaths = new Set<string>([BACKUP_MANIFEST_PATH])
for (const descriptor of descriptors) {
if (expectedPaths.has(descriptor.path)) throw new Error(`Manifest contains a duplicate path: ${descriptor.path}`)
expectedPaths.add(descriptor.path)
const staged = stagedEntries.get(descriptor.path)
if (!staged) throw new Error(`Backup entry is missing: ${descriptor.path}`)
if (staged.size !== descriptor.size) throw new Error(`Backup entry size mismatch: ${descriptor.path}`)
if (staged.checksum.value !== descriptor.checksum.value) {
throw new Error(`Backup entry checksum mismatch: ${descriptor.path}`)
}
}
for (const path of stagedEntries.keys()) {
if (!expectedPaths.has(path)) throw new Error(`Backup contains an entry not listed in manifest: ${path}`)
}
if (expectedPaths.size !== stagedEntries.size) throw new Error('Backup manifest entry list is incomplete')
validateBackupManifestGraph(manifest)
}
async function readStagedResource(storage: BackupStorage, plan: Pick<ResourceWritePlan, 'resource' | 'tempKey'>) {
const base64 = await storage.getBlob(plan.tempKey)
if (base64 === null) throw new Error(`Staged resource is missing: ${plan.resource.path}`)
return decodeStoredBlob(base64ToBytes(base64), plan.resource.encoding, plan.resource.mimeType)
}
async function findAvailableCollisionKey(storage: BackupStorage, originalKey: string, reserved: Set<string>) {
for (let attempt = 0; attempt < 100; attempt++) {
let candidatePrefix = 'resource:imported'
for (const prefix of ['picture:', 'file:', 'link:', 'parseFile-', 'parseUrl-']) {
if (originalKey.startsWith(prefix)) {
candidatePrefix = `${prefix}imported`
break
}
}View on GitHub (pinned to 81571269ad)
Solutions
- Treat as a code defect: audit validateManifestEntries and the descriptor list construction for missing/duplicate handling.
- Ensure stagedEntries and the manifest descriptors are not mutated concurrently during validation.
- Add a unit test with a known-good archive to confirm the invariant holds.
- Report with the full manifest if it reproduces.
Defensive patterns
Strategy: try-catch
Validate before calling
// No data-level pre-check applies; the invariant should be unreachable. In tests, assert it
// never fires for a corpus of well-formed archives.
for (const archive of validArchives) {
const staged = await stage(archive)
validateManifestEntries(parseManifest(archive), staged) // must not throw
} Try / catch
try {
await importBackupArchive(file, options)
} catch (error) {
if (error instanceof Error && error.message === 'Backup manifest entry list is incomplete') {
// Treat as a bug in validateManifestEntries or a concurrent-mutation issue.
throw new Error('Internal invariant violated; report this archive', { cause: error })
}
throw error
} Prevention
- Do not mutate the stagedEntries map or manifest concurrently with import.
- Add regression tests covering duplicate, missing, and extra entries so this guard stays unreachable.
- If it ever fires, preserve the archive and manifest for a code-level audit.
When it happens
Trigger: expectedPaths.size !== stagedEntries.size after the duplicate/missing/unexpected checks all passed - only reachable through a bug in descriptor construction or set bookkeeping.
Common situations: Essentially unreachable with a well-formed archive; indicates a regression in validateManifestEntries, a manifest schema that permits duplicate-but-distinct descriptors, or concurrent mutation of stagedEntries during validation.
Related errors
- Manifest contains a duplicate path: ${descriptor.path}
- Backup entry is missing: ${descriptor.path}
- Backup contains an entry not listed in manifest: ${path}
- Could not allocate a resource key for: ${originalKey}
- Resource was not staged: ${resource.path}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/a0331adfd1dbff7d.
Report an issue: GitHub.