benbjohnson/litestream · error

snapshot retention must be greater than 0

Error message

snapshot retention must be greater than 0

What it means

Sentinel error ErrInvalidSnapshotRetention is returned by Config.Validate when a configured snapshot retention is present but <= 0. Snapshot retention controls how long snapshots are kept, so a non-positive value is invalid and rejected during config validation. It is wrapped in ConfigValidationError identifying the field (snapshot.retention or dbs[<id>].snapshot.retention) and value.

Source

Thrown at cmd/litestream/main.go:54

	"github.com/benbjohnson/litestream/webdav"
)

// Version is set via -ldflags "-X main.Version=..." on release and Makefile
// builds; otherwise it is resolved from embedded VCS build info at startup.
var Version = defaultVersion

func init() {
	bi, _ := debug.ReadBuildInfo()
	Version = resolveVersion(Version, bi)
}

// errStop is a terminal error for indicating program should quit.
var errStop = errors.New("stop")

// Sentinel errors for configuration validation
var (
	ErrInvalidSnapshotInterval         = errors.New("snapshot interval must be greater than 0")
	ErrInvalidSnapshotRetention        = errors.New("snapshot retention must be greater than 0")
	ErrInvalidCompactionInterval       = errors.New("compaction interval must be greater than 0")
	ErrInvalidSyncInterval             = errors.New("sync interval must be greater than 0")
	ErrInvalidL0Retention              = errors.New("l0 retention must not be negative")
	ErrInvalidL0RetentionCheckInterval = errors.New("l0 retention check interval must be greater than 0")
	ErrInvalidShutdownSyncTimeout      = errors.New("shutdown-sync-timeout must be >= 0")
	ErrInvalidShutdownSyncInterval     = errors.New("shutdown sync interval must be greater than 0")
	ErrInvalidHeartbeatURL             = errors.New("heartbeat URL must be a valid HTTP or HTTPS URL")
	ErrInvalidHeartbeatInterval        = errors.New("heartbeat interval must be at least 1 minute")
	ErrConfigFileNotFound              = errors.New("config file not found")
)

// ConfigValidationError wraps a validation error with additional context
type ConfigValidationError struct {
	Err   error
	Field string
	Value interface{}
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Set snapshot.retention to a positive duration (e.g. "720h" for 30 days) or remove the key to use the default.
  2. If you intend to rely on cloud lifecycle policies instead, configure that at the storage provider level and keep a valid positive retention here.
  3. Fix the templating/source that produced the zero value.

Example fix

# before
snapshot:
  retention: 0
# after
snapshot:
  retention: 720h
Defensive patterns

Strategy: validation

Validate before calling

func validSnapshotRetention(d time.Duration) bool { return d > 0 }
if cfg.Snapshot != nil && cfg.Snapshot.Retention != nil && *cfg.Snapshot.Retention <= 0 {
    return errors.New("snapshot.retention must be > 0")
}

Try / catch

if err := cfg.Validate(); err != nil {
    var ve *main.ConfigValidationError
    if errors.As(err, &ve) && errors.Is(ve.Err, main.ErrInvalidSnapshotRetention) {
        return fmt.Errorf("retention %v at %s is invalid", ve.Value, ve.Field)
    }
    return err
}

Prevention

When it happens

Trigger: Setting snapshot.retention <= 0 at the top level or inside a dbs[] snapshot block; loading a config where retention was computed as 0 (e.g. empty variable or unit typo like "0h").

Common situations: Attempting to 'disable' retention by setting it to 0 (use retention disabling options instead); mistyping a duration so it parses to zero; generated configs with missing defaults.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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