can1357/oh-my-pi · critical · Error

Unable to serialize database backup: ${sourcePath}

Error message

Unable to serialize database backup: ${sourcePath}

What it means

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.

Source

Thrown at packages/mnemopi/src/dr/recovery.ts:162

export function createBackup(dbPath?: string | null, backupDir?: string | null): BackupResult {
	const paths = getDefaultPaths();
	const sourcePath = dbPath ?? paths.dbPath;
	const destinationDir = backupDir ?? paths.backupDir;

	if (!existsSync(sourcePath)) throw new FileNotFoundError(`Database not found: ${sourcePath}`);

	mkdirSync(destinationDir, { recursive: true });
	const timestamp = timestampForBackup();

	let snapshot: Uint8Array | null = null;
	let sourceDb: Database | null = null;
	try {
		sourceDb = openDatabase(sourcePath, { create: false, readwrite: false, pragmas: false });
		snapshot = (sourceDb as SerializableDatabase).serialize();
	} finally {
		closeQuietly(sourceDb);
	}
	if (snapshot === null) throw new Error(`Unable to serialize database backup: ${sourcePath}`);
	const backupPath = writeBackupFile(destinationDir, timestamp, gzipSync(snapshot));

	const dbBytes = readFileSync(sourcePath);
	const backupBytes = readFileSync(backupPath);
	const metadata: BackupMetadata = {
		timestamp,
		original_size: statSync(sourcePath).size,
		backup_size: statSync(backupPath).size,
		db_checksum: sha256Hex16(dbBytes),
		backup_checksum: sha256Hex16(backupBytes),
		compressed: true,
	};
	const metadataPath = `${backupPath.slice(0, -3)}.gz.json`;
	writeFileSync(metadataPath, `${JSON.stringify(metadata, null, 2)}\n`);

	return { backup_path: backupPath, metadata_path: metadataPath, ...metadata };
}
function isSqliteFile(bytes: Uint8Array): boolean {

View on GitHub (pinned to 9690622007)

Solutions

  1. Check db integrity (PRAGMA integrity_check) and repair or restore the source db before backing up
  2. Fall back to a file-copy backup (copy dbPath directly, ideally after a checkpoint) if serialize is unavailable
  3. Upgrade the sqlite/bun runtime to a version with reliable Database.serialize support

Example fix

// before
snapshot = (sourceDb as SerializableDatabase).serialize(); // returns null
// after
if (snapshot === null) {
	// fallback: checkpoint then byte-copy
	execSync(`sqlite3 ${sourcePath} "PRAGMA wal_checkpoint(TRUNCATE);"`);
	copyFileSync(sourcePath, fallbackCopy);
}
Defensive patterns

Strategy: fallback

Validate before calling

const db = openDatabase(sourcePath, { create: false, readwrite: false, pragmas: false });
const integrity = db.query("PRAGMA quick_check(1)").get();
if (integrity?.quick_check !== "ok") throw new Error(`db corrupt: ${sourcePath}`);
db.close();

Try / catch

try {
	createBackup(dbPath, backupDir);
} catch (err) {
	if (err.message.startsWith("Unable to serialize database backup")) {
		logger.error("serialize failed, falling back to file copy", { dbPath });
		copyFileSync(dbPath, join(backupDir, `manual-${Date.now()}.db`));
	} else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/32771f181a4cc798. Report an issue: GitHub.