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

  1. 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).
  2. If the manifest was hand-edited, restore the original or fix the duplicate path.
  3. 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

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


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