etcd-io/etcd · error
unexpected sort in delete
Error message
unexpected sort in delete
What it means
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.
Source
Thrown at client/v3/op.go:283
}
// OpDelete returns "delete" operation based on given key and operation options.
func OpDelete(key string, opts ...OpOption) Op {
// WithPrefix and WithFromKey are not supported together
if IsOptsWithPrefix(opts) && IsOptsWithFromKey(opts) {
panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one")
}
ret := Op{t: tDeleteRange, key: []byte(key)}
ret.applyOpts(opts)
switch {
case ret.leaseID != 0:
panic("unexpected lease in delete")
case ret.limit != 0:
panic("unexpected limit in delete")
case ret.rev != 0:
panic("unexpected revision in delete")
case ret.sort != nil:
panic("unexpected sort in delete")
case ret.serializable:
panic("unexpected serializable in delete")
case ret.countOnly:
panic("unexpected countOnly in delete")
case ret.minModRev != 0, ret.maxModRev != 0:
panic("unexpected mod revision filter in delete")
case ret.minCreateRev != 0, ret.maxCreateRev != 0:
panic("unexpected create revision filter in delete")
case ret.filterDelete, ret.filterPut:
panic("unexpected filter in delete")
case ret.createdNotify:
panic("unexpected createdNotify in delete")
}
return ret
}
// OpPut returns "put" operation based on given key-value and operation options.
func OpPut(key, val string, opts ...OpOption) Op {View on GitHub (pinned to f744d457f4)
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.
Example fix
// before _, err := cli.Delete(ctx, "/logs/", clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortAscend)) // panics // after _, err := cli.Delete(ctx, "/logs/", clientv3.WithPrefix())
Defensive patterns
Strategy: validation
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Shared option helpers; copy-paste from a listing routine into the matching purge routine; IDE auto-completing sort options into a delete call.
Related errors
- unexpected lease in delete
- unexpected limit in delete
- unexpected revision in delete
- unexpected serializable in delete
- unexpected countOnly in delete
AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15).
Data as JSON: /api/errors/42c57e7225952384.
Report an issue: GitHub.