{"record":{"id":"0dec715a63d034bf","repo":"can1357/oh-my-pi","slug":"restored-database-failed-integrity-check-backup","errorCode":null,"errorMessage":"Restored database failed integrity check: ${backupPath}","messagePattern":"Restored database failed integrity check: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/mnemopi/src/dr/recovery.ts","lineNumber":265,"sourceCode":"\nexport function restoreBackup(backupPath: string, dbPath?: string | null): RestoreResult {\n\tconst targetPath = dbPath ?? getDefaultPaths().dbPath;\n\tif (!existsSync(backupPath)) throw new FileNotFoundError(`Backup not found: ${backupPath}`);\n\n\tmkdirSync(dirname(targetPath), { recursive: true });\n\n\tconst uncompressed = gunzipSync(readFileSync(backupPath));\n\tconst tempPath = restoreTempPath(targetPath);\n\tlet replacedTarget = false;\n\ttry {\n\t\twriteRestoreCandidate(uncompressed, tempPath);\n\t\tif (!verifyIntegrity(tempPath)) throw new Error(`Backup failed integrity check: ${backupPath}`);\n\t\tsnapshotCurrentDatabase(targetPath);\n\t\trenameSync(tempPath, targetPath);\n\t\treplacedTarget = true;\n\t\tremoveSqliteSidecars(targetPath);\n\t\tconst integrity = verifyIntegrity(targetPath);\n\t\tif (!integrity) throw new Error(`Restored database failed integrity check: ${backupPath}`);\n\t\treturn {\n\t\t\trestored: true,\n\t\t\tbackup_used: backupPath,\n\t\t\tdatabase_path: targetPath,\n\t\t\tintegrity_check: integrity,\n\t\t};\n\t} catch (error) {\n\t\ttry {\n\t\t\trmSync(tempPath, { force: true });\n\t\t} catch {\n\t\t\t// Preserve the restore failure.\n\t\t}\n\t\tif (replacedTarget) {\n\t\t\ttry {\n\t\t\t\trestoreCurrentDatabaseSnapshot(targetPath);\n\t\t\t} catch {\n\t\t\t\t// Preserve the restore failure.\n\t\t\t}","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/dr/recovery.ts#L247-L283","documentation":"After restoreBackup() atomically renames the verified candidate over the live database and removes SQLite sidecar files, it runs verifyIntegrity() once more on the installed file. If the restored database at targetPath still fails the integrity check, it throws this error. Unlike the pre-check failure, the live database has already been replaced at this point, so the snapshot taken by snapshotCurrentDatabase() is the recovery path.","triggerScenarios":"verifyIntegrity(targetPath) returns false after renameSync(tempPath, targetPath) and removeSqliteSidecars(targetPath) — i.e. the post-rename on-disk state is corrupt even though the temp candidate passed.","commonSituations":"Failing disk/filesystem corruption during rename, leftover stale -wal/-shm sidecars interfering, another process writing to targetPath mid-restore, or filesystems without atomic rename semantics (some network mounts).","solutions":["Restore the pre-restore snapshot created by snapshotCurrentDatabase() back over targetPath.","Close all processes holding targetPath open, delete any residual -wal/-shm files, and rerun restoreBackup().","Run `sqlite3 targetPath 'PRAGMA integrity_check;'` to inspect the damage and attempt `.recover` to salvage data.","Check filesystem health (dmesg, fsck) — repeated post-rename corruption usually indicates hardware/storage failure."],"exampleFix":"// before\nconst result = restoreBackup(backupPath, dbPath);\n// after\ntry {\n  const result = restoreBackup(backupPath, dbPath);\n} catch (err) {\n  if (String(err).includes('Restored database failed integrity check')) {\n    const snapshot = findLatestSnapshot(dbPath); // file written by snapshotCurrentDatabase\n    copyFileSync(snapshot, dbPath);\n    console.error('Restored snapshot; investigate storage health');\n  }\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"// Ensure no other process holds the target open and no stale sidecars exist before restoring:\nimport { existsSync, unlinkSync } from 'node:fs';\nfor (const suffix of ['-wal', '-shm', '-journal']) {\n  const sidecar = targetPath + suffix;\n  if (existsSync(sidecar)) unlinkSync(sidecar);\n}","typeGuard":"function restoreSucceeded(r) {\n  return r != null && r.restored === true && r.integrity_check === true;\n}","tryCatchPattern":"try {\n  const result = restoreBackup(backupPath, targetPath);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Restored database failed integrity check')) {\n    restoreSnapshot(targetPath); // snapshotCurrentDatabase wrote one before the rename\n  }\n  throw err;\n}","preventionTips":["Stop all writers to targetPath before restoring","Keep the pre-restore snapshot path handy for rollback","Run on local (non-network) filesystems so rename is atomic","Check storage health if this error repeats"],"tags":["sqlite","integrity-check","restore","data-corruption","filesystem"],"backgroundTag":"database-integrity-check-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}