chatboxai/chatbox · error · Error
Manifest contains a duplicate path: ${descriptor.path}
Error message
Manifest contains a duplicate path: ${descriptor.path} What it means
Thrown by validateManifestEntries when two manifest descriptors (settings, copilots, sessionSettings, a session, or a resource) share the same archive path. Each entry must occupy a unique path so staging and checksum verification are unambiguous. Propagates out of importBackupArchive after rollback.
Source
Thrown at src/renderer/packages/backup/import-backup.ts:90
}
}
function parseJson(bytes: Uint8Array, path: string): unknown {
if (bytes.length > MAX_BACKUP_JSON_ENTRY_BYTES) throw new Error(`Backup JSON entry is too large: ${path}`)
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)) as unknown
}
function validateManifestEntries(manifest: BackupManifest, stagedEntries: Map<string, StagedEntry>) {
const descriptors = [
manifest.data.settings,
manifest.data.copilots,
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}`)View on GitHub (pinned to 81571269ad)
Solutions
- Regenerate the backup so the exporter assigns unique paths (safeSessionPathComponent already dedupes via sha256; a real collision points to duplicate source ids or an encoder bug).
- If the manifest was hand-edited, restore the original or fix the duplicate path.
- For two colliding session ids, rename one in the source data before re-export.
Example fix
// before: importing a manifest with two descriptors at the same path
await importBackupArchive(file, options)
// after: detect duplicate descriptor paths before importing
const paths = descriptors.map((d) => d.path)
if (new Set(paths).size !== paths.length) {
throw new Error('Manifest has duplicate paths: ' + paths.filter((p, i) => paths.indexOf(p) !== i))
} Defensive patterns
Strategy: validation
Validate before calling
// Before import, fail fast on duplicate descriptor paths in the manifest.
const paths = [
manifest.data.settings?.path,
manifest.data.copilots?.path,
manifest.data.sessionSettings?.path,
...manifest.sessions.map((s) => s.path),
...manifest.resources.map((r) => r.path),
].filter(Boolean) as string[]
if (new Set(paths).size !== paths.length) {
throw new Error('Manifest declares duplicate paths')
} Try / catch
try {
await importBackupArchive(file, options)
} catch (error) {
if (error instanceof Error && error.message.startsWith('Manifest contains a duplicate path')) {
// Regenerate the backup; do not attempt to merge paths by hand.
throw new Error('Backup manifest is inconsistent; re-create it', { cause: error })
}
throw error
} Prevention
- Trust the exporter's safeSessionPathComponent to assign unique paths; do not hand-edit manifests.
- Avoid duplicate session ids in source data before exporting.
- Validate manifest path uniqueness immediately after parsing the manifest, before staging.
When it happens
Trigger: A manifest where, for example, two sessions derive the same sessions/<id>/session.json path (collision after safeSessionPathComponent sha256 fallback), or a resource path collides with another descriptor's path.
Common situations: Two sessions whose ids hash to the same sha256 prefix producing duplicate session.json paths; a hand-crafted or tampered manifest; a bug in path generation during export.
Related errors
- Unsupported backup entry: ${entry.path}
- Session id does not match manifest: ${descriptor.path}
- Backup JSON entry is too large: ${path}
- Backup entry is missing: ${descriptor.path}
- Backup contains an entry not listed in manifest: ${path}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/ea2816beb2ddcbf3.
Report an issue: GitHub.