{"record":{"id":"dbdb974c03503f6c","repo":"benbjohnson/litestream","slug":"truncate-w","errorCode":null,"errorMessage":"truncate: %w","messagePattern":"truncate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":991,"sourceCode":"\n\t\tif phdr.Pgno == 1 && len(data) >= 28 {\n\t\t\tdata[18], data[19] = 0x01, 0x01\n\t\t\t_, _ = rand.Read(data[24:28])\n\t\t}\n\n\t\toff := int64(phdr.Pgno-1) * int64(pageSize)\n\t\tif _, err := f.WriteAt(data, off); err != nil {\n\t\t\treturn fmt.Errorf(\"write page %d: %w\", phdr.Pgno, err)\n\t\t}\n\t}\n\n\tif hdr.Commit > 0 {\n\t\tif err := f.Sync(); err != nil {\n\t\t\treturn fmt.Errorf(\"sync before truncate: %w\", err)\n\t\t}\n\t\tnewSize := int64(hdr.Commit) * int64(pageSize)\n\t\tif err := f.Truncate(newSize); err != nil {\n\t\t\treturn fmt.Errorf(\"truncate: %w\", err)\n\t\t}\n\t}\n\n\tif err := dec.Close(); err != nil {\n\t\treturn fmt.Errorf(\"close decoder: %w\", err)\n\t}\n\n\treturn f.Sync()\n}\n\n// fillFollowGap attempts to bridge a gap in level 0 files by searching\n// higher compaction levels for a file that covers the missing TXID range.\nfunc (r *Replica) fillFollowGap(ctx context.Context, f *os.File, afterTXID ltx.TXID, gapMinTXID ltx.TXID, pageSize uint32) (ltx.TXID, error) {\n\tcurrentTXID := afterTXID\n\n\tfor level := 1; level < SnapshotLevel; level++ {\n\t\titr, err := r.Client.LTXFiles(ctx, level, 0, false)\n\t\tif err != nil {","sourceCodeStart":973,"sourceCodeEnd":1009,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L973-L1009","documentation":"applyLTXFile truncates the database file to hdr.Commit * pageSize bytes to match the committed size from the LTX transaction header. Failure here means the OS rejected the truncate (f.Truncate), leaving the local file at the wrong size, so the transaction cannot be considered applied.","triggerScenarios":"f.Truncate(newSize) fails: read-only filesystem, permission denied on the file, newSize beyond filesystem/device limits, or an invalid hdr.Commit/pageSize combination producing an out-of-range size.","commonSituations":"Database file made read-only after a crash, running litestream as a user without write access, tiny tmpfs/disk where the committed size exceeds available space, corrupted LTX header yielding a nonsensical commit size.","solutions":["Ensure the database file and its directory are writable by the litestream user (chown/chmod)","Verify the volume is mounted read-write and has room for the target size","Validate the LTX file header (hdr.Commit) is sane; reset corrupted state with `litestream reset <db>`","Re-run restore/replication after fixing permissions or space"],"exampleFix":"# before\n$ ls -l db.sqlite\n-r--r--r-- 1 root root ... db.sqlite\n# after\n$ sudo chmod u+w db.sqlite && sudo chown litestream:litestream db.sqlite","handlingStrategy":"validation","validationCode":"fi, err := os.Stat(dbPath)\nif err != nil { return err }\nif fi.Mode().Perm()&0200 == 0 {\n    return fmt.Errorf(\"db file %s is not writable\", dbPath)\n}\nif fi.Size() > int64(hdr.Commit)*int64(pageSize) {\n    // shrink truncate expected; ensure space/perm, otherwise file may be locked read-only\n    return fmt.Errorf(\"truncate target %d < current %d; check file state\", int64(hdr.Commit)*int64(pageSize), fi.Size())\n}","typeGuard":null,"tryCatchPattern":"if err := r.applyLTXFile(ctx, f, info, pageSize); err != nil {\n    if errors.Is(err, syscall.EACCES) || errors.Is(err, syscall.EROFS) {\n        return fmt.Errorf(\"cannot truncate %s: fix permissions/mount: %w\", dbPath, err)\n    }\n    return err\n}","preventionTips":["Ensure litestream runs as a user with write access to the DB file","Check mount options (rw, not ro) after crash recovery","Size volumes for the committed database size plus headroom","Validate LTX headers if commit sizes look implausible"],"tags":["filesystem","truncate","permissions","replication"],"backgroundTag":"file-write-failed","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"}