benbjohnson/litestream · error

config file not found

Error message

config file not found

What it means

ErrConfigFileNotFound is returned by OpenConfigFile when the config file passed via -config (or the default path) does not exist on disk. The filename is wrapped into the message with fmt.Errorf %w so errors.Is still matches.

Source

Thrown at cmd/litestream/main.go:63

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

func (e *ConfigValidationError) Unwrap() error {
	return e.Err

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check the path exists: ls the exact filename passed to -config
  2. Create the config file at DefaultConfigPath() if you intended default behavior
  3. Use an absolute path instead of a relative one
  4. Handle errors.Is(err, ErrConfigFileNotFound) in code that tolerates missing configs

Example fix

// before
litestream -config litestream.yml  // run from wrong cwd
// after
litestream -config /etc/litestream/litestream.yml
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
    return fmt.Errorf("config file %s does not exist", cfgPath)
}

Try / catch

if err := litestreamRun(ctx); err != nil {
    if errors.Is(err, main.ErrConfigFileNotFound) {
        slog.Error("config missing; generate one with 'litestream config'", "err", err)
        os.Exit(1)
    }
    return err
}

Prevention

When it happens

Trigger: Calling OpenConfigFile(filename) where os.Open returns os.IsNotExist — i.e. the -config path is wrong, the file was deleted, or the default config path is absent while no explicit path was given.

Common situations: Running litestream with -config /etc/litestream.yml on a fresh install where the file was never created, typo in the filename, or running from a different working directory with a relative path.

Understand the failure class

Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.

Related errors


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