{"record":{"id":"d123f23b4b2c923a","repo":"benbjohnson/litestream","slug":"driver-does-not-implement-filecontrol","errorCode":null,"errorMessage":"driver does not implement FileControl","messagePattern":"driver does not implement FileControl","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":1011,"sourceCode":"\t\t\t\t\"duration\", time.Since(startTime))\n\t\t\treturn fmt.Errorf(\"after %d attempts: %w\", attempt, ErrShutdownInterrupted)\n\t\t}\n\t}\n}\n\n// setPersistWAL sets the PERSIST_WAL file control on the database connection.\n// This prevents SQLite from removing the WAL file when connections close.\nfunc (db *DB) setPersistWAL(ctx context.Context) error {\n\tconn, err := db.db.Conn(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get connection: %w\", err)\n\t}\n\tdefer conn.Close()\n\n\treturn conn.Raw(func(driverConn interface{}) error {\n\t\tfc, ok := driverConn.(sqlite.FileControl)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"driver does not implement FileControl\")\n\t\t}\n\n\t\t_, err := fc.FileControlPersistWAL(\"main\", 1)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"FileControlPersistWAL: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// init initializes the connection to the database.\n// Skipped if already initialized or if the database file does not exist.\nfunc (db *DB) init(ctx context.Context) (err error) {\n\t// Exit if already initialized.\n\tif db.db != nil {\n\t\treturn nil\n\t}","sourceCodeStart":993,"sourceCodeEnd":1029,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L993-L1029","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (go.mod)\nrequire modernc.org/sqlite v1.18.0 // lacks FileControl\n// after\nrequire modernc.org/sqlite v1.29.10 // implements sqlite.FileControl\n","handlingStrategy":"type-guard","validationCode":"import \"modernc.org/sqlite\"\nvar _ sqlite.FileControl = ??? // at build time, verify driver version:\n// go list -m modernc.org/sqlite  → ensure >= version with FileControl\ntypFileControl := func(dc any) (sqlite.FileControl, bool) {\n    fc, ok := dc.(sqlite.FileControl)\n    return fc, ok\n}\n","typeGuard":"func asFileControl(driverConn any) (sqlite.FileControl, bool) {\n    fc, ok := driverConn.(sqlite.FileControl)\n    return fc, ok\n}\n","tryCatchPattern":"err := dbConn.Raw(func(dc any) error {\n    fc, ok := dc.(sqlite.FileControl)\n    if !ok {\n        return fmt.Errorf(\"driver does not implement FileControl\")\n    }\n    _, err := fc.FileControlPersistWAL(\"main\", 1)\n    return err\n})\nif err != nil { log.Fatal(err) }\n","preventionTips":["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"],"tags":["sqlite","driver","type-assertion","dependency-version"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}