{"record":{"id":"f561b1963924176c","repo":"benbjohnson/litestream","slug":"page-map-w","errorCode":null,"errorMessage":"page map: %w","messagePattern":"page map: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":2082,"sourceCode":"\t\t\t}\n\t\t} else if err != nil {\n\t\t\treturn result, fmt.Errorf(\"new wal reader with offset: %w\", err)\n\t\t}\n\t}\n\n\t// Build a mapping of changed page numbers and their latest content.\n\tdb.setSyncDiagPhase(diagPhaseSyncPageMap,\n\t\tfunc(s *diagState) {\n\t\t\ts.txID = txID\n\t\t\ts.snapshotting = info.snapshotting\n\t\t\ts.reason = info.reason\n\t\t})\n\tif info.snapshotting {\n\t\tmaxSyncWALBytes = 0\n\t}\n\tpageMap, maxOffset, walCommit, limited, err := rd.pageMap(ctx, maxSyncWALBytes)\n\tif err != nil {\n\t\treturn result, fmt.Errorf(\"page map: %w\", err)\n\t}\n\tresult.limited = limited\n\tif walCommit > 0 {\n\t\tcommit = walCommit\n\t}\n\tvar sz int64\n\tif maxOffset > 0 {\n\t\tsz = maxOffset - info.offset\n\t}\n\tassert(sz >= 0, fmt.Sprintf(\"wal size must be positive: sz=%d, maxOffset=%d, info.offset=%d\", sz, maxOffset, info.offset))\n\tdb.setSyncDiagPhase(diagPhaseSyncPrepareLTX,\n\t\tfunc(s *diagState) {\n\t\t\ts.txID = txID\n\t\t\ts.walSize = sz\n\t\t\ts.snapshotting = info.snapshotting\n\t\t\ts.reason = info.reason\n\t\t})\n","sourceCodeStart":2064,"sourceCodeEnd":2100,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L2064-L2100","documentation":"WALReader.pageMap failed while building the map of changed page numbers and latest frame contents, bounded by maxSyncWALBytes. This scan is the core of staging a sync; a read or parse error mid-scan aborts the whole sync for this iteration.","triggerScenarios":"rd.pageMap(ctx, maxSyncWALBytes) errors: I/O read failure mid-WAL, a frame whose checksum/validation fails, context cancellation, or a commit frame inconsistent with earlier frames.","commonSituations":"WAL being rewritten concurrently by SQLite during the scan; corrupted WAL frames after a crash; disk errors; huge WALs hitting I/O timeouts under memory pressure.","solutions":["Retry — transient races with live checkpointing typically succeed on the next sync","Force a checkpoint via the application (PRAGMA wal_checkpoint(TRUNCATE)) and restart Litestream for a clean snapshot","Check for WAL corruption; restore from backup if frames are physically damaged","Verify disk health and sufficient I/O headroom for large WALs"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure WAL is at least header-sized and stable before sync\nst, err := os.Stat(dbPath + \"-wal\")\nready := err == nil && st.Size() >= 32","typeGuard":null,"tryCatchPattern":"if err := db.SyncAndWait(ctx); err != nil && strings.Contains(err.Error(), \"page map\") {\n\tif !errors.Is(err, context.Canceled) {\n\t\tbackoffRetry(err)\n\t}\n}","preventionTips":["Configure retention/compaction so WALs don't grow unbounded between syncs","Sync frequently (short sync intervals) to keep per-sync WAL scans small","Monitor ctx cancellations vs real I/O errors separately","Watch for disk hardware errors in dmesg when this repeats"],"tags":["sqlite","wal","page-map"],"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-14T05:17:10.506Z"}