benbjohnson/litestream · error

fetch db position: %w

Error message

fetch db position: %w

What it means

Store.CompactDB failed reading the database's current write position via db.Pos() while shortcutting the snapshot-level compaction path. db.Pos() reads the in-memory replication position of the open database, so failures here indicate internal state inconsistency (the position is normally cached). The underlying cause is wrapped with %w.

Source

Thrown at store.go:790

		return nil, &DBNotReadyError{Reason: "page size not initialized"}
	}

	dstLevel := lvl.Level

	// Ensure we are not re-compacting before the most recent compaction time.
	prevCompactionAt := lvl.PrevCompactionAt(time.Now())
	dstInfo, err := db.MaxLTXFileInfo(ctx, dstLevel)
	if err != nil {
		return nil, fmt.Errorf("fetch dst level info: %w", err)
	} else if dstInfo.CreatedAt.After(prevCompactionAt) {
		return nil, ErrCompactionTooEarly
	}

	// Shortcut if this is a snapshot since we are not pulling from a previous level.
	if dstLevel == SnapshotLevel {
		pos, err := db.Pos()
		if err != nil {
			return nil, fmt.Errorf("fetch db position: %w", err)
		}
		if dstInfo.MaxTXID != 0 && dstInfo.MaxTXID >= pos.TXID {
			return nil, ErrNoCompaction
		}

		info, err := db.Snapshot(ctx)
		if err != nil {
			return info, err
		}
		db.Logger.InfoContext(ctx, "snapshot complete", "txid", info.MaxTXID.String(), "size", info.Size)
		return info, nil
	}

	// Fetch latest LTX files for both the source & destination so we can see if we need to make progress.
	srcLevel := s.levels.PrevLevel(dstLevel)
	srcInfo, err := db.MaxLTXFileInfo(ctx, srcLevel)
	if err != nil {
		return nil, fmt.Errorf("fetch src level info: %w", err)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure the DB is open and running when compaction monitors execute; do not close the DB while compaction is in flight.
  2. Retry the compaction cycle; the monitor (monitorCompactionLevel) will attempt the next interval anyway.
  3. If persistent, restart Litestream to rebuild DB state.
  4. Report a bug with the wrapped error if Pos() consistently fails on a healthy, open database.

Example fix

// before
_, err := store.CompactDB(ctx, db, litestream.SnapshotLevel)
// after
_, err := store.CompactDB(ctx, db, litestream.SnapshotLevel)
if err != nil && db.SyncStatus() != litestream.SyncStatusRunning {
    // skip compaction: DB not in a running state
}
Defensive patterns

Strategy: retry

Validate before calling

if db.SyncStatus() != litestream.SyncStatusRunning {
    return fmt.Errorf("db not running; skip compaction")
}

Type guard

func dbHealthy(db *litestream.DB) bool {
    return db != nil && db.SyncStatus() == litestream.SyncStatusRunning
}

Try / catch

if _, err := store.CompactDB(ctx, db, litestream.SnapshotLevel); err != nil {
    // compaction monitor retries next cycle; treat as recoverable
    log.Printf("snapshot compaction deferred: %v", err)
}

Prevention

When it happens

Trigger: CompactDB(ctx, db, SnapshotLevel) where db.Pos() returns an error instead of the cached TXID position.

Common situations: Calling compaction on a DB that is in an unexpected internal state (closed concurrently, not fully initialized), or an internal bug/race between store monitoring and DB shutdown.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/778c08cdc206f9e2. Report an issue: GitHub.