benbjohnson/litestream · error

shutdown sync interval must be greater than 0

Error message

shutdown sync interval must be greater than 0

What it means

Sentinel error ErrInvalidShutdownSyncInterval is returned by Config.Validate when shutdown-sync-interval is configured but <= 0. This interval controls the polling frequency of the final sync loop during shutdown and must be positive. Wrapped in ConfigValidationError with Field "shutdown-sync-interval".

Source

Thrown at cmd/litestream/main.go:60

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{}
}

func (e *ConfigValidationError) Error() string {
	if e.Value != nil {
		return fmt.Sprintf("%s: %v (got %v)", e.Field, e.Err, e.Value)
	}
	return fmt.Sprintf("%s: %v", e.Field, e.Err)
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Set shutdown-sync-interval to a small positive duration (e.g. "1s"), or remove the key for the default.
  2. If you want an immediate shutdown sync, lower the timeout/interval semantics via shutdown-sync-timeout rather than zeroing the interval.
  3. Fix the generating template or variable expansion producing zero.

Example fix

# before
shutdown-sync-interval: 0
# after
shutdown-sync-interval: 1s
Defensive patterns

Strategy: validation

Validate before calling

if cfg.ShutdownSyncInterval != nil && *cfg.ShutdownSyncInterval <= 0 {
    return errors.New("shutdown-sync-interval 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.ErrInvalidShutdownSyncInterval) {
        return fmt.Errorf("shutdown sync interval %v invalid", ve.Value)
    }
    return err
}

Prevention

When it happens

Trigger: Setting shutdown-sync-interval: 0 or negative in the top-level config; Validate rejects the config before litestream starts.

Common situations: Setting 0 intending the tightest possible polling (choose a small positive value like 1s instead); templated configs with unset variables; copy-paste edits dropping the unit so the value parses to zero.

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/66d030cf4865975e. Report an issue: GitHub.