benbjohnson/litestream · error

cannot specify index & timestamp to restore

Error message

cannot specify index & timestamp to restore

What it means

Replica.Restore rejects mutually exclusive targeting: you may restore to a specific TXID or to a specific timestamp, but not both at once, since the two targets can conflict. Passing both a non-zero opt.TXID and a non-zero opt.Timestamp triggers this validation error before any restore work begins.

Source

Thrown at replica.go:613

}

// Replica restores the database from a replica based on the options given.
// This method will restore into opt.OutputPath, if specified, or into the
// DB's original database path. It can optionally restore from a specific
// replica or it will automatically choose the best one. Finally,
// a timestamp can be specified to restore the database to a specific
// point-in-time.
//
// When the replica contains both v0.3.x and LTX format backups, this method
// compares snapshots from both formats and uses whichever has the better backup:
// - With timestamp: uses the format with the most recent snapshot before timestamp
// - Without timestamp: uses the format with the most recent backup overall
func (r *Replica) Restore(ctx context.Context, opt RestoreOptions) (err error) {
	// Validate options.
	if opt.OutputPath == "" {
		return fmt.Errorf("output path required")
	} else if opt.TXID != 0 && !opt.Timestamp.IsZero() {
		return fmt.Errorf("cannot specify index & timestamp to restore")
	} else if opt.Follow && opt.TXID != 0 {
		return fmt.Errorf("cannot use follow mode with -txid")
	} else if opt.Follow && !opt.Timestamp.IsZero() {
		return fmt.Errorf("cannot use follow mode with -timestamp")
	} else if opt.IntegrityCheck != IntegrityCheckNone && opt.IntegrityCheck != IntegrityCheckQuick && opt.IntegrityCheck != IntegrityCheckFull {
		return fmt.Errorf("unsupported integrity check mode: %d", opt.IntegrityCheck)
	}

	// In follow mode, if the database already exists, attempt crash recovery
	// by reading the last applied TXID from the sidecar file.
	if opt.Follow {
		if _, statErr := os.Stat(opt.OutputPath); statErr == nil {
			txid, readErr := ReadTXIDFile(opt.OutputPath)
			if readErr != nil {
				return fmt.Errorf("read txid file for crash recovery: %w", readErr)
			}
			if txid == 0 {
				return fmt.Errorf("cannot resume follow mode: database exists but no -txid file found; delete the database to re-restore: %s", opt.OutputPath)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Choose one target: set either TXID or Timestamp in RestoreOptions, not both.
  2. Prefer Timestamp for point-in-time recovery; use TXID only when you know the exact transaction.
  3. Sanitize option-building code to zero the other field when one is selected.

Example fix

// before
opt := litestream.RestoreOptions{TXID: txid, Timestamp: ts}
err := replica.Restore(ctx, opt) // fails

// after
opt := litestream.RestoreOptions{Timestamp: ts} // or TXID, not both
err := replica.Restore(ctx, opt)
Defensive patterns

Strategy: validation

Validate before calling

if opt.TXID != 0 && !opt.Timestamp.IsZero() {
    return fmt.Errorf("set either TXID or Timestamp, not both")
}

Try / catch

if err := replica.Restore(ctx, opt); err != nil && strings.Contains(err.Error(), "cannot specify index & timestamp") {
    // rebuild options with a single target and retry
}

Prevention

When it happens

Trigger: Calling Restore with RestoreOptions where TXID != 0 and Timestamp is also set — e.g. code that fills both fields from user input without checking exclusivity, or CLI/config plumbing that passes both -txid and -timestamp through.

Common situations: UIs or scripts that forward all optional restore parameters unconditionally; users specifying both a transaction and a point-in-time; EnsureExists/Run callers combining stored TXID with a computed timestamp.

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


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