From cbf7dfcf65e7bdfd7e0c012e10e80430ddfb8484 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Wed, 1 Apr 2026 16:55:07 +0200 Subject: [PATCH] fix: guard MetadataCache methods against use after close Add early-return guards to getHeaders, getIndex, getManifest, and updateCachedAt when the DB has been closed. This prevents "statement has been finalized" errors when the process exit handler closes the DB while async operations are still in flight. Also change store controller close to flush (not close) the metadata DB, since the exit handler handles cleanup. --- cache/metadata/src/index.ts | 4 ++++ store/connection-manager/src/createNewStoreController.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cache/metadata/src/index.ts b/cache/metadata/src/index.ts index b28d8e7011..9a293f79dc 100644 --- a/cache/metadata/src/index.ts +++ b/cache/metadata/src/index.ts @@ -184,6 +184,7 @@ export class MetadataCache { * Cheap — no manifest data touched. */ getHeaders (name: string): MetadataHeaders | undefined { + if (this.closed) return undefined const pending = this.findPendingIndex(name) if (pending) { return { @@ -204,6 +205,7 @@ export class MetadataCache { * Does NOT load per-version manifests — very cheap. */ getIndex (name: string): MetadataIndex | null { + if (this.closed) return null const pending = this.findPendingIndex(name) if (pending) { return { @@ -238,6 +240,7 @@ export class MetadataCache { * Get a single version's manifest. Falls back from requested type to 'full'. */ getManifest (name: string, version: string, type: string): string | null { + if (this.closed) return null const pending = this.findPendingManifest(name, version, type) if (pending) return pending.manifest const row = sqliteRetry(() => this.stmtGetManifest.get(name, version, type, type)) as { manifest: string } | undefined @@ -297,6 +300,7 @@ export class MetadataCache { * Update cachedAt without rewriting data. */ updateCachedAt (name: string, cachedAt: number): void { + if (this.closed) return sqliteRetry(() => { this.stmtUpdateCachedAt.run(cachedAt, name) }) diff --git a/store/connection-manager/src/createNewStoreController.ts b/store/connection-manager/src/createNewStoreController.ts index 4340ba8761..2f53d1baa3 100644 --- a/store/connection-manager/src/createNewStoreController.ts +++ b/store/connection-manager/src/createNewStoreController.ts @@ -141,7 +141,7 @@ export async function createNewStoreController ( const origClose = ctrl.close.bind(ctrl) ctrl.close = async () => { await origClose() - metadataDb.close() + metadataDb.flush() } return { ctrl,