{"record":{"id":"079367099eb9fdb2","repo":"benbjohnson/litestream","slug":"remote-has-newer-transactions-than-expected","errorCode":null,"errorMessage":"remote has newer transactions than expected","messagePattern":"remote has newer transactions than expected","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vfs.go","lineNumber":41,"sourceCode":"\n\tlru \"github.com/hashicorp/golang-lru/v2\"\n\t\"github.com/markusmobius/go-dateparser\"\n\t\"github.com/superfly/ltx\"\n\n\t\"github.com/psanford/sqlite3vfs\"\n)\n\nconst (\n\tDefaultPollInterval = 1 * time.Second\n\tDefaultCacheSize    = 10 * 1024 * 1024 // 10MB\n\tDefaultPageSize     = 4096             // SQLite default page size\n\n\tpageFetchRetryAttempts = 6\n\tpageFetchRetryDelay    = 15 * time.Millisecond\n)\n\n// ErrConflict is returned when the remote replica has newer transactions than expected.\nvar ErrConflict = errors.New(\"remote has newer transactions than expected\")\n\nvar (\n\t//go:linkname sqlite3vfsFileMap github.com/psanford/sqlite3vfs.fileMap\n\tsqlite3vfsFileMap map[uint64]sqlite3vfs.File\n\n\t//go:linkname sqlite3vfsFileMux github.com/psanford/sqlite3vfs.fileMux\n\tsqlite3vfsFileMux sync.Mutex\n\n\tvfsConnectionMap sync.Map // map[uintptr]uint64\n)\n\n// VFS implements the SQLite VFS interface for Litestream.\n// It is intended to be used for read replicas that read directly from S3.\n// When WriteEnabled is true, also supports writes with periodic sync.\ntype VFS struct {\n\tclient ReplicaClient\n\tlogger *slog.Logger\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L23-L59","documentation":"ErrConflict is returned when the remote replica has newer transactions than the local VFS/reader expected, meaning the local view is stale relative to the replica. In the sqlite3vfs layer (vfs.go:41) it signals that a read/write cannot proceed safely against the remote transaction log without resyncing. The tests use it to assert conflicts are NOT falsely raised in normal operation.","triggerScenarios":"A page fetch or transaction read encounters a remote TXID newer than the locally expected transaction; writes issued through the litestream VFS while another process advanced the replica ahead; stale cached page/txn state after a remote compaction or restore.","commonSituations":"Two clients writing through the VFS against the same replica; a remote restore/compaction happened between reads; cached replica metadata outlived a remote write by another host.","solutions":["Close and reopen the database (or the VFS file) so local state is refreshed from the current replica position","Trigger a fresh sync/restore to pull the newer transactions before retrying writes","Ensure only one writer works against a given replica at a time; litestream is a disaster-recovery tool, not a multi-master system","Check for a real conflict: compare remote TXID vs expected before assuming stale local state"],"exampleFix":"// before\nif _, err := sqldb.Exec(\"INSERT ...\", v); err != nil {\n    return err\n}\n// after\nif _, err := sqldb.Exec(\"INSERT ...\", v); err != nil {\n    if errors.Is(err, litestream.ErrConflict) {\n        reopenAndResync() // refresh local state from replica, then retry once\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// compare remote TXID with local expected before writing\nremoteTXID, err := store.CurrentTXID(ctx, dbPath)","typeGuard":"func isConflict(err error) bool {\n    return errors.Is(err, litestream.ErrConflict) || strings.Contains(err.Error(), \"conflict\")\n}","tryCatchPattern":"if _, err := sqldb.Exec(\"INSERT ...\", v); err != nil {\n    if isConflict(err) {\n        if err := resyncAndReopen(ctx); err != nil { return err } // refresh from replica, retry once\n    }\n    return err\n}","preventionTips":["Enforce a single writer per replica","Resync after remote restore/compaction operations before writing","Avoid caching replica TXIDs across process restarts","Treat conflict as 'stale local state' and reopen rather than retry blindly"],"tags":["conflict","vfs","replication","stale-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}