benbjohnson/litestream · error
driver does not implement FileControl
Error message
driver does not implement FileControl
What it means
Litestream requires the underlying SQLite driver to expose the FileControl interface so it can issue the PERSIST_WAL file control, which keeps the WAL file from being deleted when database connections close. The code reaches into the raw driver connection via database/sql's Conn.Raw and asserts it to sqlite.FileControl; if the registered 'sqlite' driver's connection type does not implement that interface, the assertion fails and this error is returned. It effectively means the litestream binary was linked against an incompatible (usually too old) version of modernc.org/sqlite.
Source
Thrown at db.go:1011
"duration", time.Since(startTime))
return fmt.Errorf("after %d attempts: %w", attempt, ErrShutdownInterrupted)
}
}
}
// 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
}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Run `go get modernc.org/sqlite@latest` (or at least a version that implements FileControl) and rebuild: `go build -o bin/litestream ./cmd/litestream`
- Run `go mod tidy` and inspect `go mod graph | grep modernc.org/sqlite` to find a dependency forcing an older version, then upgrade or add an explicit require
- If vendoring, refresh the vendor directory with `go mod vendor` after upgrading so the new driver code is present
- Verify no alternative driver is registered under the name 'sqlite' that shadows modernc.org/sqlite's driver
Example fix
// before (go.mod) require modernc.org/sqlite v1.18.0 // lacks FileControl // after require modernc.org/sqlite v1.29.10 // implements sqlite.FileControl
Defensive patterns
Strategy: type-guard
Validate before calling
import "modernc.org/sqlite"
var _ sqlite.FileControl = ??? // at build time, verify driver version:
// go list -m modernc.org/sqlite → ensure >= version with FileControl
typFileControl := func(dc any) (sqlite.FileControl, bool) {
fc, ok := dc.(sqlite.FileControl)
return fc, ok
}
Type guard
func asFileControl(driverConn any) (sqlite.FileControl, bool) {
fc, ok := driverConn.(sqlite.FileControl)
return fc, ok
}
Try / catch
err := dbConn.Raw(func(dc any) error {
fc, ok := dc.(sqlite.FileControl)
if !ok {
return fmt.Errorf("driver does not implement FileControl")
}
_, err := fc.FileControlPersistWAL("main", 1)
return err
})
if err != nil { log.Fatal(err) }
Prevention
- Pin modernc.org/sqlite to a recent version in go.mod and commit it
- Run `go mod tidy && go mod vendor` after dependency changes and rebuild
- Avoid registering alternative drivers under the 'sqlite' name in the same binary
- Add a startup smoke test that opens a temp DB and calls FileControlPersistWAL
When it happens
Trigger: Calling DB.init -> db.setPersistWAL: the connection obtained from db.db.Conn(ctx) returns a raw driver connection whose concrete type does not satisfy sqlite.FileControl, so the type assertion driverConn.(sqlite.FileControl) in conn.Raw fails. This happens when the module graph resolves modernc.org/sqlite to a version predating FileControl/FileControlPersistWAL support, or when a different driver named 'sqlite' was registered and wins driver lookup.
Common situations: Building litestream from source with a stale go.mod pin or vendor directory containing an old modernc.org/sqlite; a downstream application importing litestream as a library that also pins an older modernc.org/sqlite, causing a downgrade via MVS; vendoring tools pruning or replacing the driver; using a fork or alternative pure-Go 'sqlite' driver that lacks FileControl.
Understand the failure class
Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.
Related errors
- open database: %w
- FileControlPersistWAL: %w
- open database for integrity check: %w
- database does not exist: %w
- open database: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/d123f23b4b2c923a.
Report an issue: GitHub.