benbjohnson/litestream · error

failed to expand meta path for %s: %w

Error message

failed to expand meta path for %s: %w

What it means

When 'meta-path' is set with directory replication, newDBFromDirectoryEntry expands environment variables in it to obtain the base meta path before deriving a per-database path from the relative path. Failure of the expand step is wrapped with the database path.

Source

Thrown at cmd/litestream/main.go:897

	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)
		if err != nil {
			return nil, fmt.Errorf("failed to configure replica for %s: %w", dbPath, err)
		}
		dbConfigCopy.Replica = replicaCopy
	}

	// Also handle deprecated 'replicas' array field.
	if len(dbc.Replicas) > 0 {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Export/set the referenced environment variable for the litestream process.
  2. Use a literal path in meta-path instead of variable expansion.
  3. Prefer meta-dir for directory replication so per-DB paths are derived automatically.

Example fix

# before
meta-path: $META_BASE/litestream

# after
meta-path: /var/lib/litestream/meta
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: expand(*dbc.MetaPath) returns an error — an unset/malformed environment variable reference in the meta-path value.

Common situations: meta-path contains $VAR that isn't present in the process environment (systemd unit missing Environment=, Docker env not passed); typo in the variable name.

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/9592d6a7ed06f5a1. Report an issue: GitHub.