{"record":{"id":"7577505a490b7dad","repo":"benbjohnson/litestream","slug":"cannot-access-sqlite-sidecar-path-w","errorCode":null,"errorMessage":"cannot access SQLite sidecar path: %w","messagePattern":"cannot access SQLite sidecar path: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/restore.go","lineNumber":287,"sourceCode":"\tinfo, err := os.Stat(path)\n\tif os.IsNotExist(err) {\n\t\treturn nil\n\t} else if err != nil {\n\t\treturn fmt.Errorf(\"cannot access output path: %w\", err)\n\t}\n\tif info.IsDir() {\n\t\treturn fmt.Errorf(\"cannot restore, output path is a directory: %s\", path)\n\t}\n\n\tif info.Size() > 0 && !force {\n\t\treturn fmt.Errorf(\"cannot restore, output path already exists and is not empty: %s. Use -force to overwrite\", path)\n\t}\n\n\tfor _, sidecarPath := range []string{path + \"-wal\", path + \"-shm\", path + \"-journal\"} {\n\t\tif _, err := os.Stat(sidecarPath); err == nil && !force {\n\t\t\treturn fmt.Errorf(\"cannot restore, SQLite sidecar path already exists: %s. Use -force to overwrite\", sidecarPath)\n\t\t} else if err != nil && !os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"cannot access SQLite sidecar path: %w\", err)\n\t\t}\n\t}\n\n\tfor _, removePath := range []string{path, path + \"-wal\", path + \"-shm\", path + \"-journal\"} {\n\t\tif err := os.Remove(removePath); err != nil && !os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"remove existing output path: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// loadFromURL creates a replica & updates the restore options from a replica URL.\nfunc (c *RestoreCommand) loadFromURL(ctx context.Context, replicaURL string, ifDBNotExists bool, opt *litestream.RestoreOptions) (*litestream.Replica, error) {\n\tif opt.OutputPath == \"\" {\n\t\treturn nil, &usageError{\n\t\t\tmessage: \"-o is required when restoring from a replica URL\",\n\t\t\thint:    fmt.Sprintf(\"litestream restore -o /path/to/db %s\", replicaURL),\n\t\t}","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/restore.go#L269-L305","documentation":"prepareOutputPath in the litestream restore command verifies that the restore target path and its SQLite sidecar files (-wal, -shm, -journal) can be safely written. For each sidecar path it calls os.Stat; if stat fails with an error other than NotExist (e.g. permission denied on the parent directory, or the path component is not a directory), it wraps and returns that error. This is a fail-fast guard so restore never silently proceeds into a target it cannot inspect.","triggerScenarios":"Running `litestream restore` when os.Stat on <db>-wal, <db>-shm, or <db>-journal returns a non-NotExist error: the parent directory lacks read/execute permission, a path component is a file not a directory, or an I/O error occurs while resolving the path (e.g. stale NFS mount, broken symlink loop).","commonSituations":"Restoring into a directory owned by another user or with restrictive permissions (common in Docker containers running as non-root); restoring to a path whose parent was replaced by a regular file; network filesystems returning transient EIO/ESTALE on stat.","solutions":["Check permissions on the output directory: run `ls -la` on the target path's parent and ensure the litestream process user can read/execute it","Verify every component of the target path is a directory: `stat` each component of the path","If the path is on a network mount, verify the mount is healthy (`df`, remount if stale)","Restore to a different writable path and move the file into place afterwards"],"exampleFix":"// before\nlitestream restore -o /var/lib/app/db.sqlite mydb\n// error: cannot access SQLite sidecar path: stat /var/lib/app/db.sqlite-wal: permission denied\n\n// after — fix directory ownership first\nsudo chown litestream:litestream /var/lib/app\nlitestream restore -o /var/lib/app/db.sqlite mydb","handlingStrategy":"validation","validationCode":"for _, suffix := range []string{\"-wal\", \"-shm\", \"-journal\"} {\n\tif _, err := os.Stat(outputPath + suffix); err != nil && !os.IsNotExist(err) {\n\t\t// abort: cannot inspect target\n\t}\n}\nif fi, err := os.Stat(filepath.Dir(outputPath)); err != nil || !fi.IsDir() {\n\t// abort: output directory missing or not a directory\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create the output directory with correct ownership before restoring","Run litestream as the same user that owns the target directory","Avoid restoring onto network or read-only filesystems","Stat-check the target path and sidecars in a pre-flight script"],"tags":["filesystem","permissions","restore","sqlite"],"backgroundTag":"file-read-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}