benbjohnson/litestream · critical
meta-path collision: databases %s and %s would share meta-pa
Error message
meta-path collision: databases %s and %s would share meta-path %s, causing replication state corruption
What it means
Litestream computes a metadata path for every database discovered via directory replication. If two databases would resolve to the same meta-path, both would read/write the same replication state and corrupt each other's checkpoints. The function detects this during setup and aborts, naming both colliding databases and the shared path.
Source
Thrown at cmd/litestream/main.go:855
if len(dbPaths) == 0 && !dbc.Watch {
return nil, fmt.Errorf("no SQLite databases found in directory %s with pattern %s", dirPath, dbc.Pattern)
}
// Create DB instances for each found database
var dbs []*litestream.DB
metaPaths := make(map[string]string)
for _, dbPath := range dbPaths {
db, err := newDBFromDirectoryEntry(dbc, dirPath, dbPath)
if err != nil {
return nil, fmt.Errorf("failed to create DB for %s: %w", dbPath, err)
}
// Validate unique meta-path to prevent replication state corruption
if mp := db.MetaPath(); mp != "" {
if existingDB, exists := metaPaths[mp]; exists {
return nil, fmt.Errorf("meta-path collision: databases %s and %s would share meta-path %s, causing replication state corruption", existingDB, dbPath, mp)
}
metaPaths[mp] = dbPath
}
dbs = append(dbs, db)
}
return dbs, nil
}
// newDBFromDirectoryEntry creates a DB instance for a database discovered via directory replication.
func newDBFromDirectoryEntry(dbc *DBConfig, dirPath, dbPath string) (*litestream.DB, error) {
// Calculate relative path from directory root
relPath, err := filepath.Rel(dirPath, dbPath)
if err != nil {
return nil, fmt.Errorf("failed to calculate relative path for %s: %w", dbPath, err)
}
View on GitHub (pinned to 4ed7a308f6)
Solutions
- Use meta-dir instead of meta-path — it derives a unique per-database path from the relative path automatically.
- Remove duplicate/symlinked files so each discovered database has a distinct relative path.
- If using a custom meta-path derivation, ensure it incorporates the per-database relative path.
- Restore only one of the colliding databases from backup instead of both.
Example fix
# before - dir: /data pattern: "*.db" meta-path: /var/lib/litestream/meta # same for every db -> collision # after - dir: /data pattern: "*.db" meta-dir: /var/lib/litestream/meta # per-db: <meta-dir>/<rel-path>.litestream
Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]string{}
for _, p := range dbPaths {
rel, _ := filepath.Rel(dirPath, p)
mp := filepath.Join(metaDir, rel+".litestream")
if prev, ok := seen[mp]; ok {
return fmt.Errorf("%s and %s collide on meta-path %s", prev, p, mp)
}
seen[mp] = p
} Prevention
- Prefer meta-dir over meta-path in directory replication configs.
- Don't symlink duplicate databases into the watched directory.
- Ensure each database has a unique relative path (no case-only differences on case-insensitive filesystems).
When it happens
Trigger: In the per-DB loop, db.MetaPath() returns a value already present in the metaPaths map — e.g. two distinct database files whose relative paths collapse to the same meta path (symlinks to the same file, case-insensitive filesystem collisions, or a custom meta-path template that doesn't vary per relative path).
Common situations: Using meta-path with a template that omits the per-DB component; symlinked duplicates in the scanned directory; a filesystem where two filenames differ only in case but the meta store is case-insensitive.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- pattern is required for directory replication
- cannot specify both 'meta-path' and 'meta-dir'
- no SQLite databases found in directory %s with pattern %s
- failed to create DB for %s: %w
- too many arguments
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/535f5a83c98778ee.
Report an issue: GitHub.