{"record":{"id":"77f6b0521a05f814","repo":"benbjohnson/litestream","slug":"cannot-use-dry-run-with-f","errorCode":null,"errorMessage":"cannot use -dry-run with -f","messagePattern":"cannot use -dry-run with -f","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/restore.go","lineNumber":198,"sourceCode":"\tLevel     int    `json:\"level\"`\n\tName      string `json:\"name\"`\n\tMinTXID   string `json:\"min_txid\"`\n\tMaxTXID   string `json:\"max_txid\"`\n\tSize      int64  `json:\"size\"`\n\tTimestamp string `json:\"timestamp\"`\n}\n\ntype RestoreResult struct {\n\tDBPath         string `json:\"db_path\"`\n\tReplica        string `json:\"replica\"`\n\tTXID           string `json:\"txid\"`\n\tDurationMS     int64  `json:\"duration_ms\"`\n\tIntegrityCheck string `json:\"integrity_check\"`\n}\n\nfunc (c *RestoreCommand) dryRunPlan(ctx context.Context, source string, r *litestream.Replica, opt litestream.RestoreOptions) (RestorePlan, error) {\n\tif opt.Follow {\n\t\treturn RestorePlan{}, fmt.Errorf(\"cannot use -dry-run with -f\")\n\t}\n\n\tinfos, err := litestream.CalcRestorePlan(ctx, r.Client, opt.TXID, opt.Timestamp, r.Logger())\n\tif err != nil {\n\t\treturn RestorePlan{}, err\n\t}\n\tif len(infos) == 0 {\n\t\treturn RestorePlan{}, litestream.ErrTxNotAvailable\n\t}\n\n\tplan := RestorePlan{\n\t\tSource:     source,\n\t\tTargetPath: opt.OutputPath,\n\t\tReplica:    r.Client.Type(),\n\t\tMinTXID:    infos[0].MinTXID.String(),\n\t\tMaxTXID:    infos[len(infos)-1].MaxTXID.String(),\n\t\tFiles:      make([]RestorePlanFile, 0, len(infos)),\n\t}","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/restore.go#L180-L216","documentation":"This error is thrown by RestoreCommand.dryRunPlan because -dry-run (which computes and prints a restore plan without restoring) and -f/-follow (which continuously restores as new WAL frames arrive) are mutually exclusive modes. A dry run produces a one-shot static plan, while follow mode never terminates, so combining them is meaningless. The command rejects the combination up front before contacting the replica.","triggerScenarios":"Running `litestream restore -dry-run -f <db path>` (or setting both DryRun and Follow in the RestoreCommand flags), which makes Run call dryRunPlan with opt.Follow == true.","commonSituations":"A user scripting a plan preview adds -f out of habit from interactive restores; a wrapper script that always appends -f; confusion between 'show me what would be restored' and 'keep restoring' semantics.","solutions":["Remove the -f/-follow flag when using -dry-run","If you want continuous restore, drop -dry-run and run the restore normally with -f","If you want a preview, run once with -dry-run (no -f), then run the real restore separately"],"exampleFix":"// before\nlitestream restore -o restored.db -dry-run -f /path/to/db\n// after\nlitestream restore -o restored.db -dry-run /path/to/db","handlingStrategy":"validation","validationCode":"if dryRun && follow {\n    return fmt.Errorf(\"-dry-run and -f are mutually exclusive\")\n}\nlitestream restore -o out.db -dry-run /path/to/db","typeGuard":null,"tryCatchPattern":"if err := cmd.Run(ctx); err != nil {\n    if strings.Contains(err.Error(), \"cannot use -dry-run with -f\") {\n        // retry without -f or without -dry-run\n    }\n    return err\n}","preventionTips":["Remember -dry-run is one-shot; -f is continuous — never combine","In wrapper scripts, add the -f flag only when not in preview mode","Validate flag combinations in CI scripts before invoking the CLI"],"tags":["cli","flags","restore"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}