benbjohnson/litestream · error
FileControlPersistWAL: %w
Error message
FileControlPersistWAL: %w
What it means
Litestream sets the PERSIST_WAL file control on the SQLite 'main' database so the -wal file survives connection close; without it, SQLite deletes the WAL and litestream cannot replicate. This error wraps a failure returned by fc.FileControlPersistWAL("main", 1) itself — the type assertion already succeeded, but the driver/SQLite rejected the operation or returned SQLITE_NOTFOUND-style errors (e.g. the schema name is wrong or the operation is unsupported for the attached database).
Source
Thrown at db.go:1016
// setPersistWAL sets the PERSIST_WAL file control on the database connection.
// This prevents SQLite from removing the WAL file when connections close.
func (db *DB) setPersistWAL(ctx context.Context) error {
conn, err := db.db.Conn(ctx)
if err != nil {
return fmt.Errorf("get connection: %w", err)
}
defer conn.Close()
return conn.Raw(func(driverConn interface{}) error {
fc, ok := driverConn.(sqlite.FileControl)
if !ok {
return fmt.Errorf("driver does not implement FileControl")
}
_, err := fc.FileControlPersistWAL("main", 1)
if err != nil {
return fmt.Errorf("FileControlPersistWAL: %w", err)
}
return nil
})
}
// init initializes the connection to the database.
// Skipped if already initialized or if the database file does not exist.
func (db *DB) init(ctx context.Context) (err error) {
// Exit if already initialized.
if db.db != nil {
return nil
}
// Exit if no database file exists.
fi, err := os.Stat(db.path)
if os.IsNotExist(err) {
return nilView on GitHub (pinned to 4ed7a308f6)
Solutions
- Inspect the wrapped inner error (%w) to identify the SQLite result code and address that root cause first
- Verify the database file opens cleanly outside litestream: `sqlite3 /path/to/db 'PRAGMA integrity_check;'` and that it can enter WAL mode
- Upgrade modernc.org/sqlite to the latest release and rebuild litestream to rule out driver regressions
- Retry litestream after ensuring no other process holds the database in a conflicting state (e.g. another tool mid-checkpoint)
Example fix
// diagnose the wrapped cause instead of the opaque wrapper
_, err := fc.FileControlPersistWAL("main", 1)
if err != nil {
return fmt.Errorf("FileControlPersistWAL: %w", err) // read the inner sqlite error
}
Defensive patterns
Strategy: try-catch
Validate before calling
// before init, check the db is healthy and writable:
// sqlite3 /path/to/db 'PRAGMA integrity_check;'
// sqlite3 /path/to/db 'PRAGMA journal_mode=wal;'
if st, err := os.Stat(dbPath); err != nil || st.IsDir() { return err }
Try / catch
if err := db.setPersistWAL(ctx); err != nil {
var inner string
fmt.Sscanf(err.Error(), "FileControlPersistWAL: %s", &inner) // inspect wrapped cause
log.Printf("persist-WAL setup failed: %v", err)
// retry init on next sync
}
Prevention
- Keep modernc.org/sqlite up to date to avoid file-control regressions
- Run integrity_check on the database before starting litestream
- Ensure no conflicting processes hold locks during litestream startup
- Log the fully unwrapped error chain (%v on the outer error preserves causes)
When it happens
Trigger: DB.init -> setPersistWAL -> conn.Raw: calling fc.FileControlPersistWAL("main", 1) returns a non-nil error. Typical causes: the driver build lacks file-control support compiled in, SQLite returns SQLITE_NOTFOUND/SQLITE_ERROR for the requested op, or the database is in a state (e.g. already closed, corrupted header) where the file control cannot run.
Common situations: Operating on a database whose file is corrupt or unreadable mid-init; using a custom build of modernc.org/sqlite with file-control stubs; an unusual DSN causing the connection to attach something other than a normal main database; rare driver regressions after upgrading modernc.org/sqlite.
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
- open database: %w
- driver does not implement FileControl
- set PERSIST_WAL: %w
- open database for integrity check: %w
- unsupported file control op: %d
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/256a1c0be21b5d17.
Report an issue: GitHub.