{"record":{"id":"32771f181a4cc798","repo":"can1357/oh-my-pi","slug":"unable-to-serialize-database-backup-sourcepath","errorCode":null,"errorMessage":"Unable to serialize database backup: ${sourcePath}","messagePattern":"Unable to serialize database backup: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/mnemopi/src/dr/recovery.ts","lineNumber":162,"sourceCode":"export function createBackup(dbPath?: string | null, backupDir?: string | null): BackupResult {\n\tconst paths = getDefaultPaths();\n\tconst sourcePath = dbPath ?? paths.dbPath;\n\tconst destinationDir = backupDir ?? paths.backupDir;\n\n\tif (!existsSync(sourcePath)) throw new FileNotFoundError(`Database not found: ${sourcePath}`);\n\n\tmkdirSync(destinationDir, { recursive: true });\n\tconst timestamp = timestampForBackup();\n\n\tlet snapshot: Uint8Array | null = null;\n\tlet sourceDb: Database | null = null;\n\ttry {\n\t\tsourceDb = openDatabase(sourcePath, { create: false, readwrite: false, pragmas: false });\n\t\tsnapshot = (sourceDb as SerializableDatabase).serialize();\n\t} finally {\n\t\tcloseQuietly(sourceDb);\n\t}\n\tif (snapshot === null) throw new Error(`Unable to serialize database backup: ${sourcePath}`);\n\tconst backupPath = writeBackupFile(destinationDir, timestamp, gzipSync(snapshot));\n\n\tconst dbBytes = readFileSync(sourcePath);\n\tconst backupBytes = readFileSync(backupPath);\n\tconst metadata: BackupMetadata = {\n\t\ttimestamp,\n\t\toriginal_size: statSync(sourcePath).size,\n\t\tbackup_size: statSync(backupPath).size,\n\t\tdb_checksum: sha256Hex16(dbBytes),\n\t\tbackup_checksum: sha256Hex16(backupBytes),\n\t\tcompressed: true,\n\t};\n\tconst metadataPath = `${backupPath.slice(0, -3)}.gz.json`;\n\twriteFileSync(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`);\n\n\treturn { backup_path: backupPath, metadata_path: metadataPath, ...metadata };\n}\nfunction isSqliteFile(bytes: Uint8Array): boolean {","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/dr/recovery.ts#L144-L180","documentation":"After opening the source database read-only, createBackup calls serialize() to snapshot it. If serialize() returns null (serialization unsupported or failed), the function throws this Error instead of writing an empty/corrupt backup. The db is closed in finally before the check.","triggerScenarios":"Opening a database that cannot be serialized (e.g. WAL state that yields null, unsupported build); serialize() failing silently on a corrupted db; a Database wrapper whose serialize returns null on failure instead of throwing.","commonSituations":"Older/patched sqlite builds without serialize support; database corrupted by a crash mid-write; memory-mapped or locked database where snapshotting fails; using a Database class from a different lib version lacking serialize.","solutions":["Check db integrity (PRAGMA integrity_check) and repair or restore the source db before backing up","Fall back to a file-copy backup (copy dbPath directly, ideally after a checkpoint) if serialize is unavailable","Upgrade the sqlite/bun runtime to a version with reliable Database.serialize support"],"exampleFix":"// before\nsnapshot = (sourceDb as SerializableDatabase).serialize(); // returns null\n// after\nif (snapshot === null) {\n\t// fallback: checkpoint then byte-copy\n\texecSync(`sqlite3 ${sourcePath} \"PRAGMA wal_checkpoint(TRUNCATE);\"`);\n\tcopyFileSync(sourcePath, fallbackCopy);\n}","handlingStrategy":"fallback","validationCode":"const db = openDatabase(sourcePath, { create: false, readwrite: false, pragmas: false });\nconst integrity = db.query(\"PRAGMA quick_check(1)\").get();\nif (integrity?.quick_check !== \"ok\") throw new Error(`db corrupt: ${sourcePath}`);\ndb.close();","typeGuard":null,"tryCatchPattern":"try {\n\tcreateBackup(dbPath, backupDir);\n} catch (err) {\n\tif (err.message.startsWith(\"Unable to serialize database backup\")) {\n\t\tlogger.error(\"serialize failed, falling back to file copy\", { dbPath });\n\t\tcopyFileSync(dbPath, join(backupDir, `manual-${Date.now()}.db`));\n\t} else throw err;\n}","preventionTips":["Run PRAGMA integrity_check before important backups","Keep the sqlite runtime current so serialize() is reliable","Avoid backing up a db mid-write; checkpoint WAL first","Alert on backup failures instead of silently skipping"],"tags":["database","backup","serialization"],"backgroundTag":"database-serialize-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}