benbjohnson/litestream · error
cannot restore, SQLite sidecar path already exists: %s. Use
Error message
cannot restore, SQLite sidecar path already exists: %s. Use -force to overwrite
What it means
prepareOutputPath also checks SQLite sidecar files (<output>-wal, <output>-shm, <output>-journal). If any of these exists and -force was not passed, restore aborts, because leaving a stale WAL/SHM/journal next to a freshly restored database can corrupt it or resurrect old data. The error names the specific sidecar path that collided.
Source
Thrown at cmd/litestream/restore.go:285
func (c *RestoreCommand) prepareOutputPath(path string, force bool) error {
info, err := os.Stat(path)
if os.IsNotExist(err) {
return nil
} else if err != nil {
return fmt.Errorf("cannot access output path: %w", err)
}
if info.IsDir() {
return fmt.Errorf("cannot restore, output path is a directory: %s", path)
}
if info.Size() > 0 && !force {
return fmt.Errorf("cannot restore, output path already exists and is not empty: %s. Use -force to overwrite", path)
}
for _, sidecarPath := range []string{path + "-wal", path + "-shm", path + "-journal"} {
if _, err := os.Stat(sidecarPath); err == nil && !force {
return fmt.Errorf("cannot restore, SQLite sidecar path already exists: %s. Use -force to overwrite", sidecarPath)
} else if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("cannot access SQLite sidecar path: %w", err)
}
}
for _, removePath := range []string{path, path + "-wal", path + "-shm", path + "-journal"} {
if err := os.Remove(removePath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove existing output path: %w", err)
}
}
return nil
}
// loadFromURL creates a replica & updates the restore options from a replica URL.
func (c *RestoreCommand) loadFromURL(ctx context.Context, replicaURL string, ifDBNotExists bool, opt *litestream.RestoreOptions) (*litestream.Replica, error) {
if opt.OutputPath == "" {
return nil, &usageError{
message: "-o is required when restoring from a replica URL",View on GitHub (pinned to 4ed7a308f6)
Solutions
- Re-run the restore with -force, which removes the stale sidecar files before restoring
- Manually delete the reported sidecar file (and the db if desired), then re-run
- Ensure no application is running against that database path, then restore
Example fix
// before rm /data/app.db litestream restore -o /data/app.db /path/to/db cannot restore, SQLite sidecar path already exists: /data/app.db-wal. Use -force to overwrite // after litestream restore -force -o /data/app.db /path/to/db
Defensive patterns
Strategy: validation
Validate before calling
for _, ext := range []string{"-wal", "-shm", "-journal"} {
if _, err := os.Stat(outputPath + ext); err == nil && !forceFlag {
return fmt.Errorf("stale sidecar %s exists; pass -force", outputPath + ext)
}
} Try / catch
if err := cmd.Run(ctx); err != nil {
if strings.Contains(err.Error(), "SQLite sidecar path already exists") {
// stop the app using that path, then re-run with -force
}
return err
} Prevention
- Stop any application using the database at the output path before restoring
- When cleaning a previous restore, remove the -wal, -shm and -journal files too, not just the .db
- Use -force for restore-into-same-path workflows so stale sidecars are removed safely
- Check for lingering sidecars with `ls /path/to/db*` before restoring
When it happens
Trigger: Restoring to a path where a previous database (or running SQLite connection) left -wal/-shm/-journal files behind, without -force. The check `os.Stat(sidecarPath); err == nil && !force` fires.
Common situations: Restoring over the location of a database that was recently in use (SQLite left the -wal/-shm behind after an unclean shutdown); retrying a restore into the same path after deleting only the .db file; a running app still holding the database at that path.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- cannot access SQLite sidecar path: %w
- remove existing output path: %w
- integrity check failed: %s
- invalid -timestamp, must specify in ISO 8601 format (e.g. 20
- database already exists, skipping
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/785af5d13f88366d.
Report an issue: GitHub.