{"record":{"id":"4327bef4f9598d45","repo":"benbjohnson/litestream","slug":"frame-salts-until-w","errorCode":null,"errorMessage":"frame salts until: %w","messagePattern":"frame salts until: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":1883,"sourceCode":"func (db *DB) detectFullCheckpoint(ctx context.Context, knownSalts [][2]uint32) (bool, error) {\n\twalFile, err := os.Open(db.WALPath())\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"open wal file: %w\", err)\n\t}\n\tdefer walFile.Close()\n\n\tvar lastKnownSalt [2]uint32\n\tif len(knownSalts) > 0 {\n\t\tlastKnownSalt = knownSalts[len(knownSalts)-1]\n\t}\n\n\trd, err := NewWALReader(walFile, db.Logger.With(LogKeySubsystem, LogSubsystemWALReader))\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"new wal reader: %w\", err)\n\t}\n\tm, err := rd.FrameSaltsUntil(ctx, lastKnownSalt)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"frame salts until: %w\", err)\n\t}\n\n\t// Remove known salts from the map.\n\tfor _, salt := range knownSalts {\n\t\tdelete(m, salt)\n\t}\n\n\t// If we have more than one unknown salt, then we have a FULL or RESTART checkpoint.\n\treturn len(m) >= 1, nil\n}\n\ntype syncInfo struct {\n\toffset              int64 // end of the previous LTX read\n\tsalt1               uint32\n\tsalt2               uint32\n\tprevCommit          uint32\n\tsnapshotting        bool   // if true, a full snapshot is required\n\treason              string // reason for snapshot","sourceCodeStart":1865,"sourceCodeEnd":1901,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L1865-L1901","documentation":"WALReader.FrameSaltsUntil failed while scanning WAL frame salts to detect whether a FULL/RESTART checkpoint occurred. Litestream compares frame salts against its known salts; an I/O or parse error mid-scan aborts detection and is wrapped and returned to the sync loop.","triggerScenarios":"rd.FrameSaltsUntil(ctx, lastKnownSalt) errors: read failure partway through the WAL (partial frame, short read), context cancellation, or a frame that fails header validation.","commonSituations":"WAL file being rewritten concurrently by SQLite checkpoint while Litestream reads it; disk I/O errors on failing hardware; ctx cancelled during shutdown; WAL truncated between open and scan.","solutions":["Retry the sync — transient races with SQLite checkpointing usually resolve on the next iteration","Check for context cancellation from shutdown and treat it as a normal stop, not an incident","Run filesystem/disk health checks if errors persist","Restart Litestream to rebuild known salts after a WAL restart (salts change on RESTART checkpoints)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// no pre-call check possible; ensure ctx is live and WAL exists\nselect {\ncase <-ctx.Done():\n\treturn ctx.Err()\ndefault:\n}","typeGuard":null,"tryCatchPattern":"err := db.SyncAndWait(ctx)\nif isCancellation(err) {\n\treturn nil // normal shutdown path\n}\nif err != nil {\n\tscheduleRetryWithBackoff(err)\n}","preventionTips":["Avoid killing Litestream mid-sync; use graceful shutdown so ctx cancels cleanly","Monitor for repeated identical errors — persistent failures indicate disk issues","Let Litestream own the WAL: don't run other tools that checkpoint aggressively"],"tags":["sqlite","wal","io"],"backgroundTag":"file-read-failed","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"}