benbjohnson/litestream · error

cannot restore, output path already exists: %s

Error message

cannot restore, output path already exists: %s

What it means

Restore refuses to overwrite: the output path already exists and neither follow mode (which supports crash-recovery resume) nor an explicit overwrite option is set. Restoring over an existing file could destroy data.

Source

Thrown at replica.go:667

			_ = snapshotItr.Close()

			if latestSnapshot != nil {
				if latestSnapshot.MinTXID > txid {
					return fmt.Errorf("cannot resume follow mode: saved TXID %s is behind the earliest snapshot (min TXID %s); replica history has been pruned -- delete %s and %s-txid to re-restore", txid, latestSnapshot.MinTXID, opt.OutputPath, opt.OutputPath)
				}
				if txid > latestSnapshot.MaxTXID {
					return fmt.Errorf("cannot resume follow mode: saved TXID %s is ahead of latest snapshot (max TXID %s); delete %s and %s-txid to re-restore", txid, latestSnapshot.MaxTXID, opt.OutputPath, opt.OutputPath)
				}
			}

			r.Logger().Info("resuming follow mode from crash recovery", "txid", txid, "output", opt.OutputPath)
			return r.follow(ctx, opt.OutputPath, txid, opt.FollowInterval)
		}
	}

	// Ensure output path does not already exist.
	if _, err := os.Stat(opt.OutputPath); err == nil {
		return fmt.Errorf("cannot restore, output path already exists: %s", opt.OutputPath)
	} else if !os.IsNotExist(err) {
		return err
	}

	// Compare v0.3.x and LTX formats to find the best backup (unless TXID is specified).
	// Skip V3 format when follow mode is enabled (V3 doesn't support incremental following).
	if opt.TXID == 0 && !opt.Follow {
		if client, ok := r.Client.(ReplicaClientV3); ok {
			useV3, err := r.shouldUseV3Restore(ctx, client, opt.Timestamp)
			if err != nil {
				return err
			}
			if useV3 {
				return r.RestoreV3(ctx, opt)
			}
		}
	}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Move or delete the existing file first
  2. Restore to a different output path
  3. Use follow mode if resuming an interrupted restore
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at replica.go:667 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/0e2196c9c18b1d4e. Report an issue: GitHub.