etcd-io/etcd · error

lease ID must be 8-byte

Error message

lease ID must be 8-byte

What it means

etcd-dump-db decodes records in the 'lease' bucket by converting each bbolt key to an int64 lease ID, which etcd always serializes as exactly 8 big-endian bytes. bytesToLeaseID panics when the key length differs, meaning the tool encountered a record in the lease bucket that is not a lease key — i.e. the data dir's layout does not match what this tool version expects, or the bucket content is corrupted.

Source

Thrown at tools/etcd-dump-db/backend.go:83

	"meta":      metaDecoder,
}

func defaultDecoder(k, v []byte) {
	fmt.Printf("key=%q, value=%q\n", k, v)
}

func keyDecoder(k, v []byte) {
	rev := mvcc.BytesToBucketKey(k)
	var kv mvccpb.KeyValue
	if err := proto.Unmarshal(v, &kv); err != nil {
		panic(err)
	}
	fmt.Printf("rev=%+v, value=[key %q | val %q | created %d | mod %d | ver %d]\n", rev, string(kv.Key), string(kv.Value), kv.CreateRevision, kv.ModRevision, kv.Version)
}

func bytesToLeaseID(bytes []byte) int64 {
	if len(bytes) != 8 {
		panic(fmt.Errorf("lease ID must be 8-byte"))
	}
	return int64(binary.BigEndian.Uint64(bytes))
}

func leaseDecoder(k, v []byte) {
	leaseID := bytesToLeaseID(k)
	var lpb leasepb.Lease
	if err := proto.Unmarshal(v, &lpb); err != nil {
		panic(err)
	}
	fmt.Printf("lease ID=%016x, TTL=%ds, remaining TTL=%ds\n", leaseID, lpb.TTL, lpb.RemainingTTL)
}

func authDecoder(k, v []byte) {
	if string(k) == "authRevision" {
		rev := binary.BigEndian.Uint64(v)
		fmt.Printf("key=%q, value=%v\n", k, rev)
	} else {

View on GitHub (pinned to f744d457f4)

Solutions

  1. Rebuild/reinstall etcd-dump-db from the same etcd source tree and version as the server that produced the data dir (make build-tools from the matching tag).
  2. Double-check the --data-dir path points at the member's data dir (containing member/snap/db), not a parent or sibling directory.
  3. Validate the db before dumping: `etcdutl bbolt check <data-dir>/member/snap/db` to rule out corruption.
  4. If dumping another bucket was intended, use the iterate/dump subcommand without the lease decoder instead of iterate-leases.

Example fix

// before (tool built from wrong version, panics on lease bucket):
//   etcd-dump-db iterate-leases --data-dir /var/lib/etcd-wrong

// after
//   git checkout v3.5.X && go install ./tools/etcd-dump-db
//   etcd-dump-db iterate-leases --data-dir /var/lib/etcd
Defensive patterns

Strategy: validation

Validate before calling

// Guard before decoding (if embedding the tool's logic):
func safeBytesToLeaseID(b []byte) (int64, bool) {
	if len(b) != 8 {
		return 0, false
	}
	return int64(binary.BigEndian.Uint64(b)), true
}

Prevention

When it happens

Trigger: Running `etcd-dump-db iterate-leases --data-dir ...` (the command that routes keys through leaseDecoder) against a db whose lease bucket holds keys of a length other than 8; typically an etcd-dump-db binary built from a different release than the server that wrote the data dir.

Common situations: Using a stale tools/ checkout of etcd-dump-db against a data dir from a newer/older etcd; pointing --data-dir at the wrong subdirectory (e.g. member/wal leftover or a snap dir holding non-lease pages); a genuinely corrupted db file from an unclean shutdown.

Related errors


AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15). Data as JSON: /api/errors/dac91578686c8f46. Report an issue: GitHub.