{"record":{"id":"08d982c04bb7231b","repo":"benbjohnson/litestream","slug":"cannot-restore-output-path-is-a-directory-s","errorCode":null,"errorMessage":"cannot restore, output path is a directory: %s","messagePattern":"cannot restore, output path is a directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/restore.go","lineNumber":276,"sourceCode":"\tif opt.Follow {\n\t\treturn \"\"\n\t}\n\tinfos, err := litestream.CalcRestorePlan(ctx, r.Client, opt.TXID, opt.Timestamp, r.Logger())\n\tif err != nil || len(infos) == 0 {\n\t\treturn \"\"\n\t}\n\treturn infos[len(infos)-1].MaxTXID.String()\n}\n\nfunc (c *RestoreCommand) prepareOutputPath(path string, force bool) error {\n\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}","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/restore.go#L258-L294","documentation":"prepareOutputPath stats the output path and rejects it if it resolves to a directory. Restore must write a SQLite database file at exactly that path, and os.WriteFile/overwrite semantics cannot replace a directory, so the command fails fast instead of producing a confusing write error later.","triggerScenarios":"Running `litestream restore -o /some/dir` where /some/dir already exists as a directory (os.Stat succeeds and info.IsDir() is true).","commonSituations":"A wrapper pre-creates the output directory with `mkdir -p` before restoring (a habit from other tools); a previous restore or tool created a directory at the target; passing a directory instead of a file path by mistake.","solutions":["Pass a file path (e.g. /data/app.db) instead of a directory as the -o output path","Remove or rename the existing directory at that path, then re-run the restore","Restore into a new path inside the directory, e.g. -o /some/dir/app.db"],"exampleFix":"// before\nmkdir -p restored\nlitestream restore -o restored /path/to/db   # fails: output path is a directory\n// after\nlitestream restore -o restored/app.db /path/to/db","handlingStrategy":"validation","validationCode":"info, err := os.Stat(outputPath)\nif err == nil && info.IsDir() {\n    return fmt.Errorf(\"output path %s is a directory; pass a file path\", outputPath)\n}","typeGuard":null,"tryCatchPattern":"if err := cmd.Run(ctx); err != nil {\n    if strings.Contains(err.Error(), \"output path is a directory\") {\n        // fix the -o argument to point at a file path\n    }\n    return err\n}","preventionTips":["-o must be the target database FILE path, not a directory","Do not pre-create the output path as a directory (e.g. via mkdir -p)","If you want the file inside a directory, restore to dir/name.db"],"tags":["filesystem","path","restore"],"backgroundTag":"path-is-not-a-directory","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"}