chatboxai/chatbox · error

Resource was not staged

Error message

Resource was not staged: ${resource.path}

What it means

Thrown by createResourcePlans when a manifest resource's path has no staged entry or its staged entry lacks a tempKey. Reading normally stages every resource under a temp blob key (lines 244-248); reaching this throw means staging and the manifest disagree. Propagates after rollback.

Solutions

  1. Ensure validateManifestEntries runs before createResourcePlans (it does in importBackupArchive).
  2. Confirm isBackupResourcePath classifies every manifest resource path as a resource during the reading phase.
  3. If the manifest was edited, restore it so it matches the archive.
  4. Regenerate the backup.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before import, ensure every resource path was staged with a tempKey during reading.
for (const r of manifest.resources) {
  const staged = stagedEntries.get(r.path)
  if (!staged?.tempKey) throw new Error('Resource not staged: ' + r.path)
}

Try / catch

try {
  await importBackupArchive(file, options)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Resource was not staged')) {
    // Usually means validateManifestEntries was bypassed; re-run it before createResourcePlans.
    throw new Error('Resource staging incomplete', { cause: error })
  }
  throw error
}

Prevention

When it happens

Trigger: manifest.resources[i].path is absent from stagedEntries, or its staged entry has tempKey undefined when createResourcePlans runs.

Common situations: Normally caught earlier by validateManifestEntries (error 126). Reachable if validation was skipped, if a resource path was staged via the JSON branch instead of the resource branch due to an isBackupResourcePath mismatch, or if tempKey assignment changed.

Related errors


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

Appendix: source

Thrown at src/renderer/packages/backup/import-backup.ts:137

      }
    }
    const candidate = `${candidatePrefix}:${uuidv4()}`
    if (!reserved.has(candidate) && (await storage.getBlob(candidate)) === null) return candidate
  }
  throw new Error(`Could not allocate a resource key for: ${originalKey}`)
}

async function createResourcePlans(
  manifest: BackupManifest,
  stagedEntries: Map<string, StagedEntry>,
  storage: BackupStorage
) {
  const plans: ResourceWritePlan[] = []
  const resourceKeyMap = new Map<string, string>()
  const reserved = new Set<string>()
  for (const resource of manifest.resources) {
    const staged = stagedEntries.get(resource.path)
    if (!staged?.tempKey) throw new Error(`Resource was not staged: ${resource.path}`)
    const restoredValue = await readStagedResource(storage, { resource, tempKey: staged.tempKey })
    const targets: ResourceWritePlan['targets'] = []
    for (const originalKey of resource.originalStorageKeys) {
      const existingValue = await storage.getBlob(originalKey)
      let targetKey = originalKey
      let needsWrite = existingValue === null
      if (existingValue !== null && existingValue !== restoredValue) {
        targetKey = await findAvailableCollisionKey(storage, originalKey, reserved)
        needsWrite = true
      }
      if (reserved.has(targetKey)) {
        targetKey = await findAvailableCollisionKey(storage, originalKey, reserved)
        needsWrite = true
      }
      reserved.add(targetKey)
      resourceKeyMap.set(originalKey, targetKey)
      targets.push({ originalKey, targetKey, needsWrite })
    }

View on GitHub (pinned to 81571269ad)