{"record":{"id":"eda42da2345e52ab","repo":"etcd-io/etcd","slug":"unexpected-lease-in-delete","errorCode":null,"errorMessage":"unexpected lease in delete","messagePattern":"unexpected lease in delete","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/v3/op.go","lineNumber":277,"sourceCode":"\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: tRange, key: []byte(key)}\n\tret.applyOpts(opts)\n\treturn ret\n}\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\")","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/etcd-io/etcd/blob/f744d457f484e9f748a0700b48ef96dcf792df33/client/v3/op.go#L259-L295","documentation":"After applying options, OpDelete verifies that no read/get-only option leaked into a delete operation. WithLease sets op.leaseID, which is only meaningful for Put (attach a lease to a key); a delete has no lease to attach, so ret.leaseID != 0 panics with \"unexpected lease in delete\". The check exists because applyOpts silently stores the option and the mismatch would otherwise be dropped or mis-sent to the server.","triggerScenarios":"clientv3.OpDelete(\"/k\", clientv3.WithLease(leaseID)) or cli.Delete(ctx, \"/k\", clientv3.WithLease(id)); sharing one []OpOption built for a Put with a Delete call; helper APIs that take 'op options' and forward them to every operation type.","commonSituations":"A generic write(key, val, opts...) helper where val==\"\" routes to Delete but options still include WithLease; retry wrappers that cache options across operation kinds; team conventions that bundle lease options with key lifecycle code that also deletes on expiry handling.","solutions":["Remove WithLease from the Delete call — leases are attached on Put; deletion revokes nothing about the lease.","If the intent is 'delete the key when the lease expires', that is automatic: just attach the lease at Put time and let it expire.","If the intent is to revoke the lease, call cli.Revoke(ctx, id) instead of Delete with WithLease.","Split option lists per operation kind in shared helpers (putOpts vs delOpts)."],"exampleFix":"// before\n_, err := cli.Delete(ctx, \"/session/1\", clientv3.WithLease(sessLease.ID())) // panics\n\n// after\n_, err := cli.Delete(ctx, \"/session/1\")\n// to free the lease itself: cli.Revoke(ctx, sessLease.ID())","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep Put options (WithLease, WithPrevKV, WithIgnoreLease, WithRequireLeader) and Delete options in separate variables.","Leases attach at Put; expiry removes the key automatically — never pass WithLease to Delete.","To free a lease, call Revoke, not Delete."],"tags":["go","etcd","clientv3","delete","lease","panic","invalid-option"],"backgroundTag":null,"analyzedSha":"f744d457f484e9f748a0700b48ef96dcf792df33","analyzedAt":"2026-08-15T09:39:50.079Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}