chatboxai/chatbox · error · Error
Staged resource is missing: ${plan.resource.path}
Error message
Staged resource is missing: ${plan.resource.path} What it means
Thrown by readStagedResource when the temporary blob written during the reading phase can no longer be read back via storage.getBlob(tempKey). The temp key was just written moments earlier during staging, so a null return means the storage backend dropped or lost the blob between write and read. Propagates; because commitStarted may be true, rollback runs.
Source
Thrown at src/renderer/packages/backup/import-backup.ts:108
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
}
}
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}`)
}
View on GitHub (pinned to 81571269ad)
Solutions
- Free storage quota before importing large backups.
- Ensure no concurrent imports or cleanup routines run during import.
- Use a persistent storage backend (request IndexedDB persistence to prevent eviction).
- Retry the import in a clean session.
Example fix
// before: temp blobs vanish between staging and commit
await importBackupArchive(file, options)
// after: request persistence and verify free quota first
if (navigator.storage?.persist) await navigator.storage.persist()
const estimate = await navigator.storage?.estimate()
if (estimate && estimate.usage / estimate.quota > 0.9) {
throw new Error('Insufficient storage quota for import')
} Defensive patterns
Strategy: retry
Validate before calling
// Before import, request persistence and ensure ample free quota so temp blobs survive.
if (navigator.storage?.persist) await navigator.storage.persist()
const est = await navigator.storage?.estimate()
if (est && est.quota && est.usage / est.quota > 0.9) {
throw new Error('Free storage before importing this backup')
} Try / catch
let lastError: unknown
for (let attempt = 0; attempt < 2; attempt++) {
try {
return await importBackupArchive(file, options)
} catch (error) {
lastError = error
if (error instanceof Error && error.message.startsWith('Staged resource is missing')) continue
throw error
}
}
throw lastError Prevention
- Request persistent storage so the browser does not evict blobs mid-import.
- Prevent concurrent tabs from running cleanupTemps during an import.
- For test mocks, ensure getBlob returns null for keys that were never written.
When it happens
Trigger: During the restore/commit phase, storage.getBlob(plan.tempKey) returns null for a resource that was staged under '__chatbox_backup_import:<id>:resource:N' in the reading phase.
Common situations: IndexedDB quota pressure evicting blobs mid-import; a storage backend that does not persist blobs reliably (in-memory mock in tests); another tab/process running cleanup concurrently; private/incognito mode clearing storage mid-operation.
Related errors
- Managed resource is missing from blob storage
- Could not allocate a resource key for: ${originalKey}
- Resource was not staged: ${resource.path}
- Backup entry is too large: ${entry.path}
- Managed resource exceeds the backup size limit
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/19f8732e08638e36.
Report an issue: GitHub.