Repository navigation
Description
Version: opencode-mem 2.31.2 (latest) · Windows 11 · OpenCode V2 (OpenChamber-bundled server) · Node 26
Symptom
After plugin boot, the log fills with:
Failed to load skills for OpenCode registration: {"error":"TypeError: The database connection is not open"}
Bursts of 1–10 right after Turso legacy migration complete, one per loaded location in the same process. 196+ occurrences over 3 days. DB-backed skills are never registered after the first load. Memory search and auto-capture are not affected by this bug.
Correction (2026-10-15)
The original root-cause claim (skillsManager not reset in closeTursoAndInvalidateCaches()) is one path into the broken state, but it is not what triggers the error in practice, and patching it alone did not stop the errors. Corrected evidence and fix below.
Evidence
Live stack trace (temporary logging added to the catch in registerDbSkills):
TypeError: The database connection is not open
at prepare (.../@tursodatabase/database-common/dist/promise.js:217:23)
at all (.../@tursodatabase/database-common/dist/promise.js:463:33)
at all (.../opencode-mem/dist/services/turso/turso-db.js:108:35)
at list (.../opencode-mem/dist/services/skills/skills-manager.js:113:31)
at async registerDbSkills (.../opencode-mem/dist/v2/adapter.js:53)
SkillsManager holds a Turso handle that something else closed, while this.db and this.initPromise still cache it. Timing places the closes during boot (immediately after the migration chain), not on dispose.
Repro
Both paths reach the same broken state (scratch storagePath, no OpenCode needed):
// path 1: full close
await skillsManager.list({ enabledOnly: true }); // ok
await closeTursoAndInvalidateCaches();
await skillsManager.list({ enabledOnly: true }); // TypeError: The database connection is not open
// path 2: single-path close (what the boot-time migrators call)
await tursoConnectionManager.closeConnection(skillsManager.dbPath);
await skillsManager.list({ enabledOnly: true }); // same TypeErrorFix that works
Make getDb() detect a stale handle instead of enumerating every closer (the boot-time migration chain calls closeConnection on various paths):
async getDb() {
+ // reopen if the connection manager closed our cached handle
+ if (this.db && tursoConnectionManager.connections.get(this.dbPath) !== this.db)
+ this.reset();
await this.initialize();
if (!this.db)
throw new Error("Skills database not initialized");
return this.db;
}Still worth adding skillsManager.reset() to closeTursoAndInvalidateCaches() for the dispose path — it fixes repro path 1, but not path 2 and not the live boot-time trigger.
Status: deployed locally since 16:17 local time. Zero occurrences in ~36 minutes across 4 restarts, where every prior restart produced a burst (10, 2, 1, 5, ... errors per burst). Memory search and captures working; sandbox red/green verified.
Open question: which code closes the skills handle during boot is not pinned down (candidates: engine/legacy migrators' closeConnection calls, encryption migrator's file sweep). The guard sidesteps it.
Separate issue (not this bug): Windows single-owner Turso lock (#359). A second OpenCode process (OpenChamber's serve --service) can win the file lock and take all memory operations offline in the other process until it exits. Unrelated to the skills-handle bug.
Activity
[-]skillsManager not reset in closeTursoAndInvalidateCaches -> 'The database connection is not open' after reload[/-][+]SkillsManager keeps a stale Turso handle after boot-time closeConnection -> 'The database connection is not open' in registerDbSkills[/+]fix(skills): reopen DB after boot-time Turso close (#413)