{"record":{"id":"54e69ed62b1363fa","repo":"benbjohnson/litestream","slug":"read-position-before-sync-w","errorCode":null,"errorMessage":"read position before sync: %w","messagePattern":"read position before sync: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"store.go","lineNumber":445,"sourceCode":"\n// SyncDB forces an immediate sync for a database. If wait is true, blocks\n// until both WAL-to-LTX and LTX-to-remote sync complete. If wait is false,\n// only performs the WAL-to-LTX sync and lets the replica monitor handle upload.\n// Lock waits are context-aware: the timeout is honored while waiting for\n// the database sync executor and the replica sync lock.\nfunc (s *Store) SyncDB(ctx context.Context, path string, wait bool) (SyncDBResult, error) {\n\tdb := s.FindDB(path)\n\tif db == nil {\n\t\treturn SyncDBResult{}, fmt.Errorf(\"%w: %s\", ErrDatabaseNotFound, path)\n\t}\n\n\tif !db.IsOpen() {\n\t\treturn SyncDBResult{}, fmt.Errorf(\"%w: %s\", ErrDatabaseNotOpen, path)\n\t}\n\n\t_, beforeTXID, err := db.MaxLTX()\n\tif err != nil {\n\t\treturn SyncDBResult{}, fmt.Errorf(\"read position before sync: %w\", err)\n\t}\n\n\tif wait {\n\t\tif err := db.SyncAndWait(ctx); err != nil {\n\t\t\treturn SyncDBResult{}, fmt.Errorf(\"sync database: %w\", err)\n\t\t}\n\t} else {\n\t\tif err := db.Sync(ctx); err != nil {\n\t\t\treturn SyncDBResult{}, fmt.Errorf(\"sync database: %w\", err)\n\t\t}\n\t}\n\n\t_, afterTXID, err := db.MaxLTX()\n\tif err != nil {\n\t\treturn SyncDBResult{}, fmt.Errorf(\"read position after sync: %w\", err)\n\t}\n\n\tvar replicatedTXID uint64","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/store.go#L427-L463","documentation":"Store.SyncDB failed before performing the sync because it could not read the database's current replication position via db.MaxLTX(). The wrapped error (ErrDatabaseNotOpen, storage errors, or internal position-lookup failures) is preserved with %w. SyncDB reports this position so callers can compare before/after TXIDs, so any failure reading it aborts the whole call.","triggerScenarios":"Store.SyncDB(ctx, path, wait) is called with a path that is not registered/open in the Store (db.IsOpen() false -> ErrDatabaseNotOpen), or MaxLTX() fails while consulting the local LTX position metadata.","commonSituations":"Calling SyncDB with a database path that was never registered via OpenDB/Config, after the DB was closed or removed from the store, a typo in the path, or racing SyncDB against Store shutdown.","solutions":["Verify the database path passed to SyncDB exactly matches a path registered with the Store (check Store output of running DBs).","Call SyncDB only after the Store has fully started and opened the database; wait for startup or use the Store's DB lookup API.","Check that the database was not closed/unregistered concurrently; serialize calls or hold a reference to the *DB.","Inspect the wrapped error (errors.Is(err, ErrDatabaseNotOpen)) to distinguish not-open from an internal MaxLTX failure."],"exampleFix":"// before\nres, err := store.SyncDB(ctx, \"/data/mydb.sqlite\", true)\n// after\nif err := store.OpenDatabase(ctx, \"/data/mydb.sqlite\"); err != nil { return err }\nres, err := store.SyncDB(ctx, \"/data/mydb.sqlite\", true)\nif err != nil && errors.Is(err, litestream.ErrDatabaseNotOpen) {\n    // path not open: look up correct path\n}","handlingStrategy":"validation","validationCode":"if store == nil || path == \"\" {\n    return fmt.Errorf(\"store and db path required\")\n}\n// look up DB in store before syncing\nif _, err := store.DB(context.Background(), path); err != nil {\n    return fmt.Errorf(\"db %q not registered: %w\", path, err)\n}","typeGuard":"func isOpen(store *litestream.Store, path string) bool {\n    db, err := store.DB(context.Background(), path)\n    return err == nil && db != nil && db.SyncStatus() != litestream.SyncStatusUnknown\n}","tryCatchPattern":"res, err := store.SyncDB(ctx, path, true)\nif err != nil {\n    if errors.Is(err, litestream.ErrDatabaseNotOpen) {\n        return fmt.Errorf(\"db %q is not open: register it with the store first\", path)\n    }\n    return err\n}","preventionTips":["Always obtain the path from the same config/registration used to create the DB","Check errors.Is(err, litestream.ErrDatabaseNotOpen) to distinguish not-open from internal failures","Avoid calling SyncDB during Store shutdown","Keep a *DB reference instead of re-resolving by path"],"tags":["go","litestream","database","sync"],"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"}