benbjohnson/litestream · error

failed to expand meta dir for %s: %w

Error message

failed to expand meta dir for %s: %w

What it means

When 'meta-dir' is set, newDBFromDirectoryEntry expands environment variables in it to get the base metadata directory before appending each database's relative path. If the expand step fails, the error is wrapped with the database path being processed.

Source

Thrown at cmd/litestream/main.go:889

		return nil, fmt.Errorf("failed to calculate relative path for %s: %w", dbPath, err)
	}

	// Create a copy of the config for the discovered database
	dbConfigCopy := *dbc
	dbConfigCopy.Path = dbPath
	dbConfigCopy.Dir = ""          // Clear dir field for individual DB
	dbConfigCopy.Pattern = ""      // Clear pattern field
	dbConfigCopy.Recursive = false // Clear recursive flag
	dbConfigCopy.Watch = false     // Individual DBs do not watch directories

	// Ensure every database discovered beneath a directory receives a unique
	// metadata path. Without this, all databases share the same meta-path and
	// clobber each other's replication state.
	switch {
	case dbc.MetaDir != nil:
		baseMetaDir, err := expand(*dbc.MetaDir)
		if err != nil {
			return nil, fmt.Errorf("failed to expand meta dir for %s: %w", dbPath, err)
		}
		metaPathCopy := filepath.Join(baseMetaDir, relPath+litestream.MetaDirSuffix)
		dbConfigCopy.MetaPath = &metaPathCopy
		dbConfigCopy.MetaDir = nil
	case dbc.MetaPath != nil:
		baseMetaPath, err := expand(*dbc.MetaPath)
		if err != nil {
			return nil, fmt.Errorf("failed to expand meta path for %s: %w", dbPath, err)
		}
		metaPathCopy := deriveMetaPathForDirectoryEntry(baseMetaPath, relPath)
		dbConfigCopy.MetaPath = &metaPathCopy
		dbConfigCopy.MetaDir = nil
	}

	// Deep copy replica config and make path unique per database.
	// This prevents all databases from writing to the same replica path.
	if dbc.Replica != nil {
		replicaCopy, err := cloneReplicaConfigWithRelativePath(dbc.Replica, relPath)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Set the referenced environment variable in the environment where litestream runs.
  2. Or replace the $VAR reference in meta-dir with a literal absolute path.
  3. Check the wrapped inner error to see which variable failed to expand.

Example fix

# before
meta-dir: $LITESTREAM_META_DIR

# after (or export LITESTREAM_META_DIR in the service unit)
meta-dir: /var/lib/litestream/meta
Defensive patterns

Strategy: validation

Validate before calling

if v := os.Getenv("LITESTREAM_META_DIR"); v == "" && strings.Contains(metaDir, "$LITESTREAM_META_DIR") {
    return fmt.Errorf("LITESTREAM_META_DIR must be set")
}

Prevention

When it happens

Trigger: expand(*dbc.MetaDir) returns an error — typically an unset or malformed environment variable reference (e.g. `meta-dir: $LITESTREAM_META` with LITESTREAM_META undefined, depending on expand's rules).

Common situations: Config template uses $VAR expansion but the environment variable isn't set in the service environment; running under systemd without an Environment= entry; variable typo.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


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