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

  1. Free up disk space at least equal to the current database size before running with -vacuum
  2. Stop other processes using the database during VACUUM
  3. Retry the command; VACUUM is atomic — a failed attempt leaves the original file intact
  4. 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

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


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