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
- Export/set the referenced environment variable for the litestream process.
- Use a literal path in meta-path instead of variable expansion.
- 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
- Verify environment variables are passed to the litestream process (Docker env, systemd unit).
- Use meta-dir for directory replication to avoid meta-path expansion entirely.
- Keep env var names consistent between deployment manifests and configs.
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
- failed to expand meta dir for %s: %w
- database config #%d: 'watch' can only be enabled with a dire
- database config #%d: 'meta-dir' can only be used with a dire
- database config #%d: cannot specify both 'meta-path' and 'me
- 'meta-dir' can only be used with a directory
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/9592d6a7ed06f5a1.
Report an issue: GitHub.