benbjohnson/litestream · error
vacuum: %w
Error message
vacuum: %w
What it means
When -vacuum is passed, shrinkDatabase runs c.runVacuum(db), executing a full `VACUUM` statement; any failure is wrapped as `vacuum: %w`. VACUUM rebuilds the entire database file to reclaim space, so it needs free disk space roughly equal to the database size plus an exclusive-ish lock for the duration. Failures typically mean insufficient disk space, a locked database, or I/O errors.
Source
Thrown at cmd/litestream-test/shrink.go:122
"size_mb", sizeAfterDelete/1024/1024,
"change_mb", (initialSize-sizeAfterDelete)/1024/1024,
)
if c.Checkpoint {
if err := c.runCheckpoint(db); err != nil {
return fmt.Errorf("checkpoint: %w", err)
}
sizeAfterCheckpoint, _ := getDatabaseSize(c.DB)
slog.Info("Size after checkpoint",
"size_mb", sizeAfterCheckpoint/1024/1024,
"change_from_delete_mb", (sizeAfterDelete-sizeAfterCheckpoint)/1024/1024,
)
}
if c.Vacuum {
if err := c.runVacuum(db); err != nil {
return fmt.Errorf("vacuum: %w", err)
}
sizeAfterVacuum, _ := getDatabaseSize(c.DB)
slog.Info("Size after VACUUM",
"size_mb", sizeAfterVacuum/1024/1024,
"total_reduction_mb", (initialSize-sizeAfterVacuum)/1024/1024,
)
}
finalSize, err := getDatabaseSize(c.DB)
if err != nil {
return fmt.Errorf("get final size: %w", err)
}
reductionPercent := float64(initialSize-finalSize) / float64(initialSize) * 100
slog.Info("Shrink operation complete",
"initial_size_mb", initialSize/1024/1024,
"final_size_mb", finalSize/1024/1024,View on GitHub (pinned to 4ed7a308f6)
Solutions
- Free up disk space at least equal to the current database size before running with -vacuum
- Stop other processes using the database during VACUUM
- Retry the command; VACUUM is atomic — a failed attempt leaves the original file intact
- Check the wrapped inner error: SQLITE_FULL means disk space, SQLITE_BUSY means locking
Example fix
// before df -h /tmp # 1GB free, database is 4GB litestream-test shrink -db /tmp/big.db -vacuum // after df -h /tmp # ensure > database size free litestream-test shrink -db /tmp/big.db -vacuum
Defensive patterns
Strategy: fallback
Validate before calling
info, err := os.Stat(dbPath)
if err == nil {
if free, ferr := diskFree(filepath.Dir(dbPath)); ferr == nil && free < 2*info.Size() {
return fmt.Errorf("insufficient disk space for VACUUM: need ~%d, have %d", info.Size(), free)
}
} Try / catch
if err := runShrink(args); err != nil {
if strings.Contains(err.Error(), "vacuum") {
if strings.Contains(err.Error(), "database or disk is full") {
log.Printf("free disk space and retry: %v", err)
} else if strings.Contains(err.Error(), "locked") {
log.Printf("stop other connections and retry: %v", err)
}
}
return err
} Prevention
- Ensure free disk space at least equal to the database size before using -vacuum
- Run VACUUM only when no other connections are using the database
- Drop -vacuum first when debugging failures — deletions and checkpoint still succeed without it
When it happens
Trigger: VACUUM on a large database with insufficient free disk space for the temporary rebuild; another connection holding a write transaction or active read preventing VACUUM's exclusive access; the connection being inside a transaction (VACUUM cannot run within one); disk quota exceeded.
Common situations: Shrinking multi-GB test databases on small CI runners or containers with tight disk quotas; running while the app is live; WAL journal mode leftovers interfering on some setups.
Related errors
- vacuum failed: %w
- create _litestream_lock table: %w
- acquire read lock: %w
- disk full
- database does not exist: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/c3982ca1e2af76eb.
Report an issue: GitHub.