Files
openclaw/src/infra/node-sqlite.ts
Vincent Koc f33ab243cf fix(sqlite): reject runtimes vulnerable to WAL corruption (#106065)
* fix(sqlite): require WAL-reset-safe Node runtime

* docs(sqlite): document safe Node runtime floor

* fix(sqlite): defer runtime library validation until use

* fix(ci): align startup memory with Node 24.15
2026-07-13 13:59:00 +08:00

56 lines
2.2 KiB
TypeScript

// Loads node:sqlite with OpenClaw warning handling.
import { createRequire } from "node:module";
import { formatErrorMessage } from "./errors.js";
import { isSqliteWalResetSafeVersion } from "./sqlite-runtime-version.js";
import { installProcessWarningFilter } from "./warning-filter.js";
const require = createRequire(import.meta.url);
let validatedSqliteModule: typeof import("node:sqlite") | undefined;
function assertSqliteWalResetSafeVersion(version: string, nodeVersion: string): void {
if (isSqliteWalResetSafeVersion(version)) {
return;
}
throw new Error(
`OpenClaw requires SQLite 3.51.3+ (or patched 3.50.7+/3.44.6+) for WAL safety; ` +
`Node ${nodeVersion} embeds SQLite ${version}, which is affected by the upstream WAL-reset ` +
"database corruption bug. Upgrade to Node 22.22.3+, 24.15.0+, or 25.9.0+ before retrying.",
);
}
function assertSafeSqliteRuntime(sqlite: typeof import("node:sqlite")): void {
if (validatedSqliteModule === sqlite) {
return;
}
// Shared-SQLite Node builds can load a different library than process.versions
// reports, so query the loaded library before callers open real state databases.
const database = new sqlite.DatabaseSync(":memory:");
try {
const row = database.prepare("SELECT sqlite_version() AS version").get() as
| { version?: unknown }
| undefined;
const version = typeof row?.version === "string" ? row.version : "unknown";
assertSqliteWalResetSafeVersion(version, process.versions.node);
validatedSqliteModule = sqlite;
} finally {
database.close();
}
}
// node:sqlite is optional across Node versions, so callers get a clear runtime
// error instead of a low-level module resolution failure.
/** Load node:sqlite after installing the process warning filter. */
export function requireNodeSqlite(): typeof import("node:sqlite") {
installProcessWarningFilter();
try {
const sqlite = require("node:sqlite") as typeof import("node:sqlite");
assertSafeSqliteRuntime(sqlite);
return sqlite;
} catch (err) {
const message = formatErrorMessage(err);
throw new Error(`SQLite support is unavailable or unsafe in this Node runtime. ${message}`, {
cause: err,
});
}
}