benbjohnson/litestream · error
page not found: %d
Error message
page not found: %d
What it means
When reading a page, the VFS looks up pgno in its page index; if the page is absent and cannot be satisfied (beyond commit, or not in any LTX index), it logs "page not found" and returns an error. This means the page index has no record of the requested page, so SQLite asked for a page the replica chain never contained.
Source
Thrown at vfs.go:1586
// Get page index element
f.mu.Lock()
elem, ok := f.index[pgno]
writeEnabled := f.writeEnabled // capture while holding lock to avoid data race
f.mu.Unlock()
if !ok {
// For write-enabled VFS with a new database (no existing pages),
// return zeros to indicate empty page. SQLite will initialize the database.
if writeEnabled {
f.logger.Debug("page not found, returning zeros for new database", "page", pgno)
for i := range p {
p[i] = 0
}
return len(p), nil
}
f.logger.Error("page not found", "page", pgno)
return 0, fmt.Errorf("page not found: %d", pgno)
}
var data []byte
var lastErr error
ctx := f.ctx
for attempt := 0; attempt < pageFetchRetryAttempts; attempt++ {
_, data, lastErr = FetchPage(ctx, f.client, elem.Level, elem.MinTXID, elem.MaxTXID, elem.Offset, elem.Size)
if lastErr == nil {
break
}
if !isRetryablePageError(lastErr) {
f.logger.Error("cannot fetch page", "page", pgno, "attempt", attempt+1, "error", lastErr)
return 0, fmt.Errorf("fetch page: %w", lastErr)
}
if attempt == pageFetchRetryAttempts-1 {
f.logger.Error("cannot fetch page after retries", "page", pgno, "attempts", pageFetchRetryAttempts, "error", lastErr)
return 0, sqlite3vfs.BusyErrorView on GitHub (pinned to 4ed7a308f6)
Solutions
- Confirm the read offset/pgno is within the file size implied by the commit header.
- Call ResetTime / re-hydrate to rebuild the page index from the replica.
- Check that the database was fully replicated (all LTX levels present) via `litestream ltx -level all`.
- If it recurs at the same pgno, validate LTX integrity — the index may be corrupt.
Defensive patterns
Strategy: validation
Validate before calling
// guard reads against the commit boundary before issuing them
if int64(off)+int64(len(p)) > int64(f.commit)*int64(f.pageSize) {
return 0, io.EOF // do not ask the VFS for pages beyond commit
} Try / catch
n, err := file.ReadAt(p, off)
if err != nil && strings.Contains(err.Error(), "page not found") {
if rerr := file.ResetTime(ctx); rerr != nil { return rerr }
n, err = file.ReadAt(p, off) // retry after index rebuild
} Prevention
- Call ResetTime after replication catch-up so the index matches the replica.
- Verify full LTX chain integrity with `litestream ltx -level all`.
- Never serve reads from a partially built or interrupted index rebuild.
When it happens
Trigger: A Read for a pgno whose entry is missing from the built index — reads past the commit boundary, a corrupted/incomplete index after ResetTime, or SQLite reading a page from a WAL/journal offset the VFS index never captured.
Common situations: Time-travel reads with a stale or partially built index; index rebuild raced with new writes; SQLite asserting a larger database size than the replica's commit header; bugs after a failed rebuild left a truncated index.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- fetch page index: %w
- read dirty page from buffer: %w
- too many arguments
- failed to format response: %w
- database config #%d: 'watch' can only be enabled with a dire
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/1e9171efab2ce101.
Report an issue: GitHub.