k3s-io/k3s · error
no etcd restore path was specified
Error message
no etcd restore path was specified
What it means
Restore performs an offline etcd restore from a snapshot and requires config.ClusterResetRestorePath to point at the snapshot file. When that field is empty the function refuses before touching any state, so nothing is moved or renamed.
Solutions
- Pass the snapshot path explicitly: k3s server --cluster-reset --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/etcd-snapshot-<date>-<tz>.zip.
- If the snapshot lives in S3, add the --etcd-s3-* flags (or config secret) so the restore can fetch it, and keep --cluster-reset-restore-path set to the snapshot name/path.
- Verify the snapshot file exists and is readable before retrying; the next check os.Stat will fail otherwise.
Example fix
# before k3s server --cluster-reset # after k3s server --cluster-reset --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/etcd-snapshot-20260801T000000Z.zip
Defensive patterns
Strategy: validation
Validate before calling
if cfg.ClusterReset && cfg.ClusterResetRestorePath == "" {
return errors.New("cluster-reset requested without a restore path; pass --cluster-reset-restore-path")
} Try / catch
if err := e.Restore(ctx); err != nil {
if strings.Contains(err.Error(), "no etcd restore path was specified") {
// operator error: fix flags and re-run; nothing was modified yet
}
return err
} Prevention
- Wrap cluster-reset automation in a pre-flight check for the snapshot path.
- Keep a documented, tested restore command per environment so the path flag is never improvised.
When it happens
Trigger: Running a cluster-reset flow (ETCD.Restore) without passing --cluster-reset-restore-path, e.g. 'k3s server --cluster-reset' with S3 options but no snapshot path, or calling Restore programmatically on a config where ClusterResetRestorePath was never set.
Common situations: Operators running --cluster-reset expecting a local restore but forgetting the snapshot argument; automation that sets --cluster-reset only; passing an S3 snapshot name where a local path is expected (S3 snapshots must be downloaded first or referenced via the s3:// flow).
Related errors
- invalid flag use; --cluster-reset required with…
- cannot perform cluster-reset while server URL is set -…
- etcd-s3-timeout must be greater than 0s
- etcd: snapshot path does not exist
- etcd: snapshot path must be a file, not a directory
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/734b3f3f34b45748.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/etcd/etcd.go:1516
if !member.IsLearner && !isSelf {
if isPreferred {
clientURLs = append(member.ClientURLs, clientURLs...)
} else {
clientURLs = append(clientURLs, member.ClientURLs...)
}
}
}
return clientURLs, memberList, nil
}
// Restore performs a restore of the ETCD datastore from
// the given snapshot path. This operation exists upon
// completion.
func (e *ETCD) Restore(ctx context.Context) error {
// check the old etcd data dir
oldDataDir := dbDir(e.config) + "-old-" + strconv.Itoa(int(time.Now().Unix()))
if e.config.ClusterResetRestorePath == "" {
return errors.New("no etcd restore path was specified")
}
// make sure snapshot exists before restoration
if _, err := os.Stat(e.config.ClusterResetRestorePath); err != nil {
return err
}
// Restore is an offline operation, so create a logger for it instead of borrowing one from
// the datastore client. Do it before anything is moved, so that we fail early.
logger, err := logutil.CreateDefaultZapLogger(zapcore.InfoLevel)
if err != nil {
return err
}
var restorePath string
if strings.HasSuffix(e.config.ClusterResetRestorePath, snapshot.CompressedExtension) {
dir, err := snapshotDir(e.config, true)
if err != nil {
return errors.WithMessage(err, "failed to get the snapshot dir")
}View on GitHub (pinned to 6ba341e396)