benbjohnson/litestream · error
failed to scan directory %s: %w
Error message
failed to scan directory %s: %w
What it means
After expanding the directory path, NewDBsFromDirectoryConfig calls FindSQLiteDatabases to enumerate databases matching the pattern. If that filesystem scan fails (I/O error rather than merely no matches), the error is wrapped with the directory path to identify what could not be scanned.
Source
Thrown at cmd/litestream/main.go:835
return nil, fmt.Errorf("directory path is required for directory replication")
}
if dbc.Pattern == "" {
return nil, fmt.Errorf("pattern is required for directory replication")
}
if dbc.MetaPath != nil && dbc.MetaDir != nil {
return nil, fmt.Errorf("cannot specify both 'meta-path' and 'meta-dir'")
}
dirPath, err := expand(dbc.Dir)
if err != nil {
return nil, err
}
// Find all SQLite databases in the directory
dbPaths, err := FindSQLiteDatabases(dirPath, dbc.Pattern, dbc.Recursive)
if err != nil {
return nil, fmt.Errorf("failed to scan directory %s: %w", dirPath, err)
}
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 != "" {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check that the configured directory exists and is readable by the litestream process at startup.
- Read the wrapped inner error to identify the failing path/file and fix the filesystem or permission problem.
- If the directory is on a network mount, add a startup dependency (systemd After=/Requires=) so the mount is ready before litestream starts.
- Exclude problematic subdirectories (narrow the pattern) if a specific path is unreadable.
Example fix
// before
dirPath, _ := expand(dbc.Dir) // mount may not be ready
// after
if _, err := os.Stat(dirPath); err != nil {
return nil, fmt.Errorf("directory %s not ready: %w", dirPath, err) // surface before scanning
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(dirPath); err != nil {
return fmt.Errorf("replication dir %s unavailable: %w", dirPath, err)
} Try / catch
if err := runLitestream(ctx); err != nil {
var scanErr *fs.PathError
if errors.As(err, &scanErr) {
log.Warnf("directory scan failed, retrying after mount check: %v", err)
}
} Prevention
- Add systemd After=/Requires= for the directory's mount unit.
- Check directory permissions for the litestream user before startup.
- Avoid recursive patterns over directories with unreadable subpaths.
When it happens
Trigger: FindSQLiteDatabases(dirPath, pattern, recursive) returns a non-nil error — e.g. the directory disappeared between expand and scan, an I/O error occurred while reading a subdirectory, or permission errors surfaced as errors from the walk.
Common situations: Directory is a mount that is not yet mounted at startup; network filesystem (NFS/EFS) hiccup; symlink loop or unreadable subdirectory under a recursive scan; container volume not attached yet.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- close L0 file: %w
- failed to calculate relative path for %s: %w
- cannot remove tmp files: %w
- get database position: %w
- remove L0 directory: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/eb12b51284b12915.
Report an issue: GitHub.