k3s-io/k3s · error

invalid snapshot operation

Error message

invalid snapshot operation

What it means

POST /db/snapshot dispatches on the request's Operation field, which must be one of list, save, prune, or delete (SnapshotOperation* constants). The default branch routes unknown operations to handleInvalid, which responds HTTP 400 with id etcd-snapshot.

Source

Thrown at pkg/etcd/snapshot_handler.go:139

func (e *ETCD) handleDelete(rw http.ResponseWriter, req *http.Request, snapshots []string) error {
	if e.config.EtcdS3 != nil {
		if _, err := e.getS3Client(req.Context()); err != nil {
			err = errors.WithMessage(err, "failed to initialize S3 client")
			util.SendError(err, rw, req, http.StatusBadRequest)
			return nil
		}
	}
	sr, err := e.DeleteSnapshots(req.Context(), snapshots)
	if sr == nil {
		util.SendError(err, rw, req, http.StatusInternalServerError)
		return nil
	}
	sendSnapshotResponse(rw, req, sr)
	return err
}

func (e *ETCD) handleInvalid(rw http.ResponseWriter, req *http.Request) error {
	util.SendErrorWithID(errors.New("invalid snapshot operation"), "etcd-snapshot", rw, req, http.StatusBadRequest)
	return nil
}

// withRequest returns a modified ETCD struct that is overridden
// with etcd snapshot config from the snapshot request.
func (e *ETCD) withRequest(sr *SnapshotRequest) *ETCD {
	re := &ETCD{
		client: e.client,
		config: &config.Control{
			CriticalControlArgs:   e.config.CriticalControlArgs,
			Runtime:               e.config.Runtime,
			DataDir:               e.config.DataDir,
			Datastore:             e.config.Datastore,
			DisableAgent:          e.config.DisableAgent,
			EtcdSnapshotCompress:  e.config.EtcdSnapshotCompress,
			EtcdSnapshotName:      e.config.EtcdSnapshotName,
			EtcdSnapshotRetention: e.config.EtcdSnapshotRetention,
			EtcdS3:                sr.S3,

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Use one of the supported operations exactly: list, save, prune, delete.
  2. Align CLI and server versions so both ends speak the same operation set.
  3. Inspect the outgoing JSON body and confirm the operation field is present and lowercase.

Example fix

# before
curl -X POST https://node:6443/db/snapshot -d '{"operation":"list-all"}'
# after
curl -X POST https://node:6443/db/snapshot -d '{"operation":"list"}'
Defensive patterns

Strategy: validation

Validate before calling

var validOps = map[string]bool{"list": true, "save": true, "prune": true, "delete": true}
if !validOps[sr.Operation] {
    return fmt.Errorf("invalid snapshot operation %q (want list|save|prune|delete)", sr.Operation)
}

Type guard

func isValidSnapshotOperation(op string) bool {
	switch op {
	case "list", "save", "prune", "delete":
		return true
	}
	return false
}

Prevention

When it happens

Trigger: Sending a SnapshotRequest whose operation is misspelled (e.g. 'List', 'lists', 'delete-snapshot') or using an operation added in a newer server than the CLI in use; hand-rolled HTTP clients omitting the operation field.

Common situations: Version skew between k3s CLI and server where operation names changed; curl scripts with typos; JSON payloads built by templating that drops the field.

Related errors


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