{"record":{"id":"42c57e7225952384","repo":"etcd-io/etcd","slug":"unexpected-sort-in-delete","errorCode":null,"errorMessage":"unexpected sort in delete","messagePattern":"unexpected sort in delete","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/v3/op.go","lineNumber":283,"sourceCode":"}\n\n// OpDelete returns \"delete\" operation based on given key and operation options.\nfunc OpDelete(key string, opts ...OpOption) Op {\n\t// WithPrefix and WithFromKey are not supported together\n\tif IsOptsWithPrefix(opts) && IsOptsWithFromKey(opts) {\n\t\tpanic(\"`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one\")\n\t}\n\tret := Op{t: tDeleteRange, key: []byte(key)}\n\tret.applyOpts(opts)\n\tswitch {\n\tcase ret.leaseID != 0:\n\t\tpanic(\"unexpected lease in delete\")\n\tcase ret.limit != 0:\n\t\tpanic(\"unexpected limit in delete\")\n\tcase ret.rev != 0:\n\t\tpanic(\"unexpected revision in delete\")\n\tcase ret.sort != nil:\n\t\tpanic(\"unexpected sort in delete\")\n\tcase ret.serializable:\n\t\tpanic(\"unexpected serializable in delete\")\n\tcase ret.countOnly:\n\t\tpanic(\"unexpected countOnly in delete\")\n\tcase ret.minModRev != 0, ret.maxModRev != 0:\n\t\tpanic(\"unexpected mod revision filter in delete\")\n\tcase ret.minCreateRev != 0, ret.maxCreateRev != 0:\n\t\tpanic(\"unexpected create revision filter in delete\")\n\tcase ret.filterDelete, ret.filterPut:\n\t\tpanic(\"unexpected filter in delete\")\n\tcase ret.createdNotify:\n\t\tpanic(\"unexpected createdNotify in delete\")\n\t}\n\treturn ret\n}\n\n// OpPut returns \"put\" operation based on given key-value and operation options.\nfunc OpPut(key, val string, opts ...OpOption) Op {","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/etcd-io/etcd/blob/f744d457f484e9f748a0700b48ef96dcf792df33/client/v3/op.go#L265-L301","documentation":"OpDelete rejects WithSort / any sort option (WithSortKeys, WithSortByXXX orderings set ret.sort). Sorting orders the KV results of a range read; a delete returns only a count of removed keys, so a sort is inapplicable. The constructor's validation switch panics with \"unexpected sort in delete\" rather than dropping the option.","triggerScenarios":"clientv3.OpDelete(\"/k/\", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)); forwarding a Get's ordering options into a cleanup Delete; table-driven code that applies one option set to every operation.","commonSituations":"Shared option helpers; copy-paste from a listing routine into the matching purge routine; IDE auto-completing sort options into a delete call.","solutions":["Remove the WithSort option from Delete calls.","If you intended 'delete oldest/newest first', page with Get+WithSort and delete the explicit keys in a Txn instead.","Keep listing options and mutation options in distinct slices/types at the call site."],"exampleFix":"// before\n_, err := cli.Delete(ctx, \"/logs/\", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortAscend)) // panics\n\n// after\n_, err := cli.Delete(ctx, \"/logs/\", clientv3.WithPrefix())","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["WithSort and its orderings only shape Get results; Delete responses carry just a count.","For ordered (e.g. oldest-first) deletion, list with Get+WithSort then delete explicit keys.","Keep listing options out of mutation paths."],"tags":["go","etcd","clientv3","delete","sort","panic","invalid-option"],"backgroundTag":null,"analyzedSha":"f744d457f484e9f748a0700b48ef96dcf792df33","analyzedAt":"2026-08-15T09:39:50.079Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}