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 datastoreView on GitHub (pinned to 6ba341e396)
Solutions
- 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`.
- If the snapshot arrived as a directory (e.g. extracted from an archive), locate the .db file inside it and pass that path.
- 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
- Use `k3s etcd-snapshot ls` output to construct restore paths exactly.
- For S3 restores, configure S3 options and pass the object path, not the bucket/prefix.
- Codify restore steps in a tested runbook script.
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
- etcd: snapshot path does not exist: %s
- invalid flag use; --cluster-reset required with --cluster-re
- Managed etcd cluster membership has been reset, restart with
- cannot use S3 config secret when restoring snapshot; configu
- unexpected compressed etcd snapshot contents
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/b24e1ca645502ba0.
Report an issue: GitHub.