{"record":{"id":"7e473bfaf4353294","repo":"k3s-io/k3s","slug":"invalid-snapshot-operation","errorCode":null,"errorMessage":"invalid snapshot operation","messagePattern":"invalid snapshot operation","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"pkg/etcd/snapshot_handler.go","lineNumber":139,"sourceCode":"func (e *ETCD) handleDelete(rw http.ResponseWriter, req *http.Request, snapshots []string) error {\n\tif e.config.EtcdS3 != nil {\n\t\tif _, err := e.getS3Client(req.Context()); err != nil {\n\t\t\terr = errors.WithMessage(err, \"failed to initialize S3 client\")\n\t\t\tutil.SendError(err, rw, req, http.StatusBadRequest)\n\t\t\treturn nil\n\t\t}\n\t}\n\tsr, err := e.DeleteSnapshots(req.Context(), snapshots)\n\tif sr == nil {\n\t\tutil.SendError(err, rw, req, http.StatusInternalServerError)\n\t\treturn nil\n\t}\n\tsendSnapshotResponse(rw, req, sr)\n\treturn err\n}\n\nfunc (e *ETCD) handleInvalid(rw http.ResponseWriter, req *http.Request) error {\n\tutil.SendErrorWithID(errors.New(\"invalid snapshot operation\"), \"etcd-snapshot\", rw, req, http.StatusBadRequest)\n\treturn nil\n}\n\n// withRequest returns a modified ETCD struct that is overridden\n// with etcd snapshot config from the snapshot request.\nfunc (e *ETCD) withRequest(sr *SnapshotRequest) *ETCD {\n\tre := &ETCD{\n\t\tclient: e.client,\n\t\tconfig: &config.Control{\n\t\t\tCriticalControlArgs:   e.config.CriticalControlArgs,\n\t\t\tRuntime:               e.config.Runtime,\n\t\t\tDataDir:               e.config.DataDir,\n\t\t\tDatastore:             e.config.Datastore,\n\t\t\tDisableAgent:          e.config.DisableAgent,\n\t\t\tEtcdSnapshotCompress:  e.config.EtcdSnapshotCompress,\n\t\t\tEtcdSnapshotName:      e.config.EtcdSnapshotName,\n\t\t\tEtcdSnapshotRetention: e.config.EtcdSnapshotRetention,\n\t\t\tEtcdS3:                sr.S3,","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/etcd/snapshot_handler.go#L121-L157","documentation":"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.","triggerScenarios":"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.","commonSituations":"Version skew between k3s CLI and server where operation names changed; curl scripts with typos; JSON payloads built by templating that drops the field.","solutions":["Use one of the supported operations exactly: list, save, prune, delete.","Align CLI and server versions so both ends speak the same operation set.","Inspect the outgoing JSON body and confirm the operation field is present and lowercase."],"exampleFix":"# before\ncurl -X POST https://node:6443/db/snapshot -d '{\"operation\":\"list-all\"}'\n# after\ncurl -X POST https://node:6443/db/snapshot -d '{\"operation\":\"list\"}'","handlingStrategy":"validation","validationCode":"var validOps = map[string]bool{\"list\": true, \"save\": true, \"prune\": true, \"delete\": true}\nif !validOps[sr.Operation] {\n    return fmt.Errorf(\"invalid snapshot operation %q (want list|save|prune|delete)\", sr.Operation)\n}","typeGuard":"func isValidSnapshotOperation(op string) bool {\n\tswitch op {\n\tcase \"list\", \"save\", \"prune\", \"delete\":\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":null,"preventionTips":["Pin CLI and server versions together in automation.","Unit-test JSON request builders against the server's operation constants."],"tags":["http","api","snapshot","validation"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}