JuliusBrussee/caveman · error

read sqlite journal mode

Error message

read sqlite journal mode: %w

What it means

This error wraps a failure to read back the current journal mode via sqliteJournalMode (PRAGMA journal_mode) after configuring it. The store reads the mode to detect filesystems that silently ignore the WAL request; if the read itself fails the open is aborted and the db closed.

Solutions

  1. Check for competing processes/locks on the database file and retry after they exit
  2. Run 'sqlite3 <path> "PRAGMA journal_mode;"' to verify the database is readable at all
  3. If the file is corrupted, restore from backup or delete and let the store recreate it
  4. Retry open with the store's RetryOnBusy semantics satisfied (ensure busy_timeout is applied)

Example fix

// before
store, err := ccr.Open(dbPath) // fails: read sqlite journal mode
// after
if _, err := os.Stat(dbPath); err == nil {
    // verify externally that the db is readable before opening
    cmd := exec.Command("sqlite3", dbPath, "PRAGMA journal_mode;")
    if err := cmd.Run(); err != nil { /* restore or recreate */ }
}
store, err := ccr.Open(dbPath)
Defensive patterns

Strategy: retry

Validate before calling

cmd := exec.Command("sqlite3", dbPath, "PRAGMA journal_mode;")
if err := cmd.Run(); err != nil {
    return fmt.Errorf("cannot read journal mode of %s: %w", dbPath, err)
}

Try / catch

store, err := ccr.Open(dbPath)
if err != nil && strings.Contains(err.Error(), "read sqlite journal mode") {
    // wait for the competing lock holder to exit, then retry
    time.Sleep(500 * time.Millisecond)
    store, err = ccr.Open(dbPath)
}

Prevention

When it happens

Trigger: The 'PRAGMA journal_mode' query inside sqliteJournalMode returns an error: locked database, corrupted file, or driver-level failure executing the query.

Common situations: Another process holding an exclusive lock; database file corrupted by a prior crash; unusual filesystems blocking pragma queries.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/23e13130e7027a8a. Report an issue: GitHub.

Appendix: source

Thrown at engine/ccr/store_sqlite.go:211

	// One writer connection. With a single connection every statement serializes
	// in-process (no self-contention) while busy_timeout absorbs cross-process
	// contention; it is also mandatory for an in-memory DSN, where a second
	// pooled connection would be a second, empty database.
	db.SetMaxOpenConns(1)
	db.SetMaxIdleConns(1)
	walJournal := false
	if canonicalPath != ":memory:" {
		if err := persistSQLiteWAL(db); err != nil {
			closeSQLiteAfterOpenFailure(db, canonicalPath)
			return nil, fmt.Errorf("configure sqlite journal: %w", err)
		}
		// A filesystem that cannot back -shm (NFS, SMB, some roaming profiles)
		// leaves the DSN's journal_mode request unapplied. Requiring the WAL
		// sidecars there would report a perfectly good database as replaced.
		mode, err := sqliteJournalMode(db)
		if err != nil {
			closeSQLiteAfterOpenFailure(db, canonicalPath)
			return nil, fmt.Errorf("read sqlite journal mode: %w", err)
		}
		walJournal = strings.EqualFold(mode, "wal")
	}
	if err := RetryOnBusy(func() error { _, e := db.Exec(schema); return e }); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("migrate sqlite %q: %w", canonicalPath, err)
	}
	if err := RetryOnBusy(func() error { return ensureMetadataColumn(db) }); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("migrate sqlite metadata %q: %w", canonicalPath, err)
	}
	if err := RetryOnBusy(func() error { return ensureDataRefColumn(db) }); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("migrate sqlite data_ref %q: %w", canonicalPath, err)
	}
	if err := configureStorageBudget(db, maxBytes); err != nil {
		closeSQLiteAfterOpenFailure(db, canonicalPath)
		return nil, fmt.Errorf("configure sqlite storage budget %q: %w", canonicalPath, err)

View on GitHub (pinned to 3ee70a1026)