k3s-io/k3s · critical

etcd: snapshot path must be a file, not a directory: %s

Error message

etcd: snapshot path must be a file, not a directory: %s

What it means

The companion check to the missing-path error: the --cluster-reset-restore-path must be a regular file containing an etcd db snapshot. If os.Stat succeeds and reports a directory, restore aborts before touching the datastore - a directory of snapshots is not a restorable artifact.

Source

Thrown at pkg/etcd/etcd.go:416

			}
			dir, err := snapshotDir(e.config, true)
			if err != nil {
				return errors.WithMessage(err, "failed to get the snapshot dir")
			}
			path, err := s3client.Download(ctx, e.config.ClusterResetRestorePath, dir)
			if err != nil {
				return errors.WithMessage(err, "failed to download snapshot from S3")
			}
			e.config.ClusterResetRestorePath = path
			logrus.Infof("S3 download complete for %s", e.config.ClusterResetRestorePath)
		}

		info, err := os.Stat(e.config.ClusterResetRestorePath)
		if os.IsNotExist(err) {
			return fmt.Errorf("etcd: snapshot path does not exist: %s", e.config.ClusterResetRestorePath)
		}
		if info.IsDir() {
			return fmt.Errorf("etcd: snapshot path must be a file, not a directory: %s", e.config.ClusterResetRestorePath)
		}
		if err := e.Restore(ctx); err != nil {
			return err
		}
	}

	if err := e.setName(true); err != nil {
		return err
	}
	// touch a file to avoid multiple resets
	if err := os.WriteFile(e.ResetFile(), []byte{}, 0600); err != nil {
		return err
	}

	return e.newCluster(ctx, wg, true)
}

// Start starts the datastore

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Point at a specific snapshot file, e.g. /var/lib/rancher/k3s/server/db/snapshots/<name>.db - find one with `k3s etcd-snapshot ls` or `ls`.
  2. If the snapshot arrived as a directory (e.g. extracted from an archive), locate the .db file inside it and pass that path.
  3. For S3 restores, pass the object path; ensure the configured S3 location actually contains the snapshot object.

Example fix

# before
k3s server --cluster-reset --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots

# after
k3s server --cluster-reset --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/etcd-snapshot-1723680000-0.db
Defensive patterns

Strategy: validation

Validate before calling

// Require a regular file, not a directory:
info, err := os.Stat(snapshotPath)
if err != nil { log.Fatal(err) }
if info.IsDir() {
    log.Fatalf("%s is a directory; pick the snapshot file inside it", snapshotPath)
}

Prevention

When it happens

Trigger: Passing a directory to --cluster-reset-restore-path, most commonly the snapshots directory itself or an S3 prefix that resolved to a directory (pkg/etcd/etcd.go:415-417).

Common situations: Operator passes /var/lib/rancher/k3s/server/db/snapshots instead of a specific .db file; unzipping/copying a snapshot into a folder and pointing at the folder; confusion between the S3 bucket path and the object key.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/b24e1ca645502ba0. Report an issue: GitHub.