{"record":{"id":"6e353fd4b3c45924","repo":"JuliusBrussee/caveman","slug":"configure-sqlite-journal-w","errorCode":null,"errorMessage":"configure sqlite journal: %w","messagePattern":"configure sqlite journal: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":203,"sourceCode":"\t\t// PrepareSQLitePathCanonical already created the file. Never recreate\n\t\t// it if it vanishes between preparation and the driver's open.\n\t\tdsn += \"&mode=rw\"\n\t}\n\tdb, err := sql.Open(\"sqlite\", dsn)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open sqlite %q: %w\", canonicalPath, err)\n\t}\n\t// One writer connection. With a single connection every statement serializes\n\t// in-process (no self-contention) while busy_timeout absorbs cross-process\n\t// contention; it is also mandatory for an in-memory DSN, where a second\n\t// pooled connection would be a second, empty database.\n\tdb.SetMaxOpenConns(1)\n\tdb.SetMaxIdleConns(1)\n\twalJournal := false\n\tif canonicalPath != \":memory:\" {\n\t\tif err := persistSQLiteWAL(db); err != nil {\n\t\t\tcloseSQLiteAfterOpenFailure(db, canonicalPath)\n\t\t\treturn nil, fmt.Errorf(\"configure sqlite journal: %w\", err)\n\t\t}\n\t\t// A filesystem that cannot back -shm (NFS, SMB, some roaming profiles)\n\t\t// leaves the DSN's journal_mode request unapplied. Requiring the WAL\n\t\t// sidecars there would report a perfectly good database as replaced.\n\t\tmode, err := sqliteJournalMode(db)\n\t\tif err != nil {\n\t\t\tcloseSQLiteAfterOpenFailure(db, canonicalPath)\n\t\t\treturn nil, fmt.Errorf(\"read sqlite journal mode: %w\", err)\n\t\t}\n\t\twalJournal = strings.EqualFold(mode, \"wal\")\n\t}\n\tif err := RetryOnBusy(func() error { _, e := db.Exec(schema); return e }); err != nil {\n\t\tcloseSQLiteAfterOpenFailure(db, canonicalPath)\n\t\treturn nil, fmt.Errorf(\"migrate sqlite %q: %w\", canonicalPath, err)\n\t}\n\tif err := RetryOnBusy(func() error { return ensureMetadataColumn(db) }); err != nil {\n\t\tcloseSQLiteAfterOpenFailure(db, canonicalPath)\n\t\treturn nil, fmt.Errorf(\"migrate sqlite metadata %q: %w\", canonicalPath, err)","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L185-L221","documentation":"This error wraps a failure to persist the WAL journal mode on the opened SQLite database (persistSQLiteWAL). The store requires WAL for concurrent readers, and if the journal mode cannot be applied/persisted the open is aborted and the half-opened db is closed. This typically means the underlying Exec setting PRAGMA journal_mode=WAL failed.","triggerScenarios":"persistSQLiteWAL's PRAGMA journal_mode=WAL statement returns an error, e.g. the database is locked by another process beyond busy_timeout, or the file is on a filesystem that rejects the operation.","commonSituations":"Databases on network mounts (NFS/SMB) where WAL cannot be established; a long-running writer in another process holding the lock; read-only file media.","solutions":["Check no other process holds a write lock on the database; increase busy_timeout if contention is heavy","Move the database to a local filesystem that supports WAL and -shm sidecar files","Run the PRAGMA journal_mode=WAL manually with the sqlite3 CLI to see the underlying failure","If WAL is impossible in your environment, configure a non-WAL journal mode explicitly if the library supports it"],"exampleFix":"// before\nrows, err := db.Query(\"SELECT data FROM ccr\") // on NFS, WAL pragma failed at open\n// after\n// relocate db to local disk:\nstore, err := ccr.Open(\"/var/lib/app/ccr.db\") // local ext4/apfs volume","handlingStrategy":"retry","validationCode":"// verify WAL is supportable before opening\nout, err := exec.Command(\"sqlite3\", dbPath, \"PRAGMA journal_mode;\").Output()\nif err != nil {\n    return fmt.Errorf(\"db %s not inspectable: %w\", dbPath, err)\n}","typeGuard":null,"tryCatchPattern":"store, err := ccr.Open(dbPath)\nif err != nil && strings.Contains(err.Error(), \"configure sqlite journal\") {\n    // fall back to local disk or retry after lock clears\n    time.Sleep(250 * time.Millisecond)\n    store, err = ccr.Open(dbPath)\n}","preventionTips":["Keep the database on a local filesystem, not NFS/SMB/cloud-sync folders","Avoid multiple long-running writers in separate processes","Pre-check journal mode with the sqlite3 CLI on exotic mounts"],"tags":["sqlite","wal","journal-mode"],"backgroundTag":"database-query-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}