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
- Set the referenced environment variable in the environment where litestream runs.
- Or replace the $VAR reference in meta-dir with a literal absolute path.
- 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
- Set all $VARs used in the config via systemd Environment= or the container env.
- Prefer literal paths when the config is deployed to fixed locations.
- Log/echo the expanded config at startup in staging.
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
- failed to expand meta path 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/12bdc23dd6ce218f.
Report an issue: GitHub.