etcd-io/etcd · error
unexpected create revision filter in delete
Error message
unexpected create revision filter in delete
What it means
OpDelete rejects WithMinCreateRev / WithMaxCreateRev. Create-revision filters are range-read predicates selecting keys created within a revision window; they have no meaning for a delete range. When applyOpts leaves ret.minCreateRev or ret.maxCreateRev non-zero, the constructor panics with "unexpected create revision filter in delete".
Source
Thrown at client/v3/op.go:291
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 {
ret := Op{t: tPut, key: []byte(key), val: []byte(val)}
ret.applyOpts(opts)
switch {
case ret.end != nil:
panic("unexpected range in put")
case ret.limit != 0:
panic("unexpected limit in put")
case ret.rev != 0:View on GitHub (pinned to f744d457f4)
Solutions
- List with Get + WithMaxCreateRev(cutoff), then delete those explicit keys in a Txn.
- If the condition is per-key, use a Txn If with CompareCreated instead.
- Strip create-rev filter options from Delete calls.
Example fix
// before
_, err := cli.Delete(ctx, "/sess/", clientv3.WithPrefix(), clientv3.WithMaxCreateRev(cutoffRev)) // panics
// after
gr, err := cli.Get(ctx, "/sess/", clientv3.WithPrefix(), clientv3.WithMaxCreateRev(cutoffRev))
var ops []clientv3.Op
for _, kv := range gr.Kvs {
ops = append(ops, clientv3.OpDelete(string(kv.Key)))
}
_, err = cli.Txn(ctx).Then(ops...).Commit() Defensive patterns
Strategy: validation
Prevention
- Create-revision filters are read predicates; retention deletes must target explicit keys.
- Use CompareCreated in a Txn If for per-key create-revision conditions.
- Split 'select stale keys' options from 'delete' options in retention code.
When it happens
Trigger: clientv3.OpDelete("/k/", clientv3.WithPrefix(), clientv3.WithMinCreateRev(rev)) — e.g. 'delete keys created before the backup revision'; option-slice sharing with a Get that used the same filter.
Common situations: Retention/GC jobs: list old keys via create-revision filters, then erroneously apply the filter to the cleanup Delete; generic option bundles in data-migration tooling.
Related errors
- unexpected mod revision filter in delete
- unexpected lease in delete
- unexpected limit in delete
- unexpected revision in delete
- unexpected sort in delete
AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15).
Data as JSON: /api/errors/4e89875d32f73e15.
Report an issue: GitHub.