dgraph-io/dgraph · critical

cannot unmarshal list part with key %s

Error message

cannot unmarshal list part with key %s

What it means

This error wraps a failure from unmarshalOrCopy when the bytes read for one part of a multi-part posting list cannot be decoded into pb.PostingList. It means the data on disk does not match the expected protobuf schema, i.e. the stored posting list part is corrupt or written by an incompatible version.

Source

Thrown at posting/list.go:2279

// readListPart reads one split of a posting list from Badger.
func (l *List) readListPart(startUid uint64) (*pb.PostingList, error) {
	key, err := x.SplitKey(l.key, startUid)
	if err != nil {
		return nil, errors.Wrapf(err,
			"cannot generate key for list with base key %s and start UID %d",
			hex.EncodeToString(l.key), startUid)
	}
	txn := pstore.NewTransactionAt(l.minTs, false)
	defer txn.Discard()
	item, err := txn.Get(key)
	if err != nil {
		return nil, errors.Wrapf(err, "could not read list part with key %s",
			hex.EncodeToString(key))
	}
	part := &pb.PostingList{}
	if err := unmarshalOrCopy(part, item); err != nil {
		return nil, errors.Wrapf(err, "cannot unmarshal list part with key %s",
			hex.EncodeToString(key))
	}
	return part, nil
}

// shouldSplit returns true if the given plist should be split in two.
func shouldSplit(plist *pb.PostingList) bool {
	return proto.Size(plist) >= maxListSize && len(plist.Pack.Blocks) > 1
}

func (out *rollupOutput) updateSplits() {
	if out.plist == nil || len(out.parts) > 0 {
		out.plist = &pb.PostingList{}
	}
	out.plist.Splits = out.splits()
}

func (out *rollupOutput) recursiveSplit() {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Restore the affected keys from a known-good backup
  2. Verify all nodes run the same Dgraph/badger version and codecs match
  3. Run badger's iterate/verify tooling to locate corrupt entries, then force re-index (drop all + re-bulk-load)
  4. Check protobuf schema compatibility if custom builds are involved
Defensive patterns

Strategy: fallback

Validate before calling

// Validate stored bytes decode before use
func partDecodable(item *badger.Item) bool {
    var pl pb.PostingList
    buf, err := item.ValueCopy(nil)
    if err != nil { return false }
    return proto.Unmarshal(buf, &pl) == nil
}

Try / catch

part, err := readListPart(key, startUid)
if err != nil && strings.Contains(err.Error(), "cannot unmarshal list part") {
    // treat as corrupt: quarantine key, alert, fall back to backup/rollup
    markCorrupt(key)
    return nil, err
}

Prevention

When it happens

Trigger: unmarshalOrCopy(part, item) returns an error while decoding a posting-list part in readListPart — typically because the value bytes are truncated, corrupted, or produced by a different protobuf schema/version.

Common situations: Upgrading/downgrading Dgraph across incompatible versions; value-log corruption after crash; copy optimization reading across mismatched snapshot data; manual data migration between clusters.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/edbf598dc9133b51. Report an issue: GitHub.