benbjohnson/litestream · error
compaction not enabled
Error message
compaction not enabled
What it means
VFSFile.Compact compacts LTX files between levels, but only if a compactor was configured on the file. When f.compactor is nil (compaction was never wired up for this VFS file), the call returns this error. Compaction is optional in the VFS path, so absence is reported explicitly rather than panicking.
Source
Thrown at vfs.go:3003
if f.vfs.L0Retention > 0 {
f.compactionWg.Add(1)
go func() {
defer f.compactionWg.Done()
f.monitorL0Retention(f.compactionCtx)
}()
}
f.logger.Info("compaction monitors started",
"levels", len(levels),
"snapshotInterval", f.vfs.SnapshotInterval,
"l0Retention", f.vfs.L0Retention)
}
// Compact compacts source level files into the destination level.
// Returns ErrNoCompaction if there are no files to compact.
func (f *VFSFile) Compact(ctx context.Context, level int) (*ltx.FileInfo, error) {
if f.compactor == nil {
return nil, fmt.Errorf("compaction not enabled")
}
return f.compactor.Compact(ctx, level)
}
// Snapshot creates a full database snapshot from remote LTX files.
// Unlike DB.Snapshot(), this reads from remote rather than local WAL.
func (f *VFSFile) Snapshot(ctx context.Context) (*ltx.FileInfo, error) {
if f.compactor == nil {
return nil, fmt.Errorf("compaction not enabled")
}
f.mu.Lock()
pageSize := f.pageSize
commit := f.commit
pos := f.pos
pages := make(map[uint32]ltx.PageIndexElem, len(f.index))
for pgno, elem := range f.index {
pages[pgno] = elemView on GitHub (pinned to 4ed7a308f6)
Solutions
- Use the DB-layer compaction API (db.go) instead of VFSFile.Compact when no VFS compactor is configured
- Configure the VFS file with a compactor at open time if you need VFS-driven compaction
- Check ErrNoCompaction handling — even with a compactor, zero files to compact returns that sentinel
- Verify your config actually enables the compaction levels you call
Example fix
// before: compacting a restore-mode VFS file info, err := vfsFile.Compact(ctx, 1) // compaction not enabled // after: compact via the DB layer info, err := db.Compact(ctx, 0, 1)
Defensive patterns
Strategy: validation
Validate before calling
if vfsFile.Compactor() == nil {
return fmt.Errorf("vfs file has no compactor; use db.Compact instead")
} Type guard
func canCompact(f *VFSFile) bool { return f != nil && f.Compactor() != nil } Try / catch
info, err := vfsFile.Compact(ctx, level)
if err != nil {
if err.Error() == "compaction not enabled" {
return db.Compact(ctx, level, level+1)
}
if errors.Is(err, litestream.ErrNoCompaction) {
return nil // nothing to compact; not fatal
}
return err
} Prevention
- Configure a compactor on the VFS file if you plan to compact via VFS
- Use DB-layer compaction for embed use cases
- Treat ErrNoCompaction as a no-op, not a failure
When it happens
Trigger: Calling VFSFile.Compact(ctx, level) on a VFS file opened without compaction support — e.g. a read-only restore-mode VFS file, or an open path that does not construct the compactor.
Common situations: Embedding app calls Compact on VFS files created for restore/read paths only; assuming VFS files share DB-layer compaction settings; feature flag or config section omitted so no compactor is built.
Related errors
- compaction interval must be greater than 0
- remote has newer transactions than expected
- fetch l1 files: %w
- fetch dst level info: %w
- fetch db position: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/74fe2815c97b57e0.
Report an issue: GitHub.