{"record":{"id":"edbf598dc9133b51","repo":"dgraph-io/dgraph","slug":"cannot-unmarshal-list-part-with-key-s","errorCode":null,"errorMessage":"cannot unmarshal list part with key %s","messagePattern":"cannot unmarshal list part with key (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"posting/list.go","lineNumber":2279,"sourceCode":"\n// readListPart reads one split of a posting list from Badger.\nfunc (l *List) readListPart(startUid uint64) (*pb.PostingList, error) {\n\tkey, err := x.SplitKey(l.key, startUid)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err,\n\t\t\t\"cannot generate key for list with base key %s and start UID %d\",\n\t\t\thex.EncodeToString(l.key), startUid)\n\t}\n\ttxn := pstore.NewTransactionAt(l.minTs, false)\n\tdefer txn.Discard()\n\titem, err := txn.Get(key)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"could not read list part with key %s\",\n\t\t\thex.EncodeToString(key))\n\t}\n\tpart := &pb.PostingList{}\n\tif err := unmarshalOrCopy(part, item); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"cannot unmarshal list part with key %s\",\n\t\t\thex.EncodeToString(key))\n\t}\n\treturn part, nil\n}\n\n// shouldSplit returns true if the given plist should be split in two.\nfunc shouldSplit(plist *pb.PostingList) bool {\n\treturn proto.Size(plist) >= maxListSize && len(plist.Pack.Blocks) > 1\n}\n\nfunc (out *rollupOutput) updateSplits() {\n\tif out.plist == nil || len(out.parts) > 0 {\n\t\tout.plist = &pb.PostingList{}\n\t}\n\tout.plist.Splits = out.splits()\n}\n\nfunc (out *rollupOutput) recursiveSplit() {","sourceCodeStart":2261,"sourceCodeEnd":2297,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/posting/list.go#L2261-L2297","documentation":"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.","triggerScenarios":"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.","commonSituations":"Upgrading/downgrading Dgraph across incompatible versions; value-log corruption after crash; copy optimization reading across mismatched snapshot data; manual data migration between clusters.","solutions":["Restore the affected keys from a known-good backup","Verify all nodes run the same Dgraph/badger version and codecs match","Run badger's iterate/verify tooling to locate corrupt entries, then force re-index (drop all + re-bulk-load)","Check protobuf schema compatibility if custom builds are involved"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Validate stored bytes decode before use\nfunc partDecodable(item *badger.Item) bool {\n    var pl pb.PostingList\n    buf, err := item.ValueCopy(nil)\n    if err != nil { return false }\n    return proto.Unmarshal(buf, &pl) == nil\n}","typeGuard":null,"tryCatchPattern":"part, err := readListPart(key, startUid)\nif err != nil && strings.Contains(err.Error(), \"cannot unmarshal list part\") {\n    // treat as corrupt: quarantine key, alert, fall back to backup/rollup\n    markCorrupt(key)\n    return nil, err\n}","preventionTips":["Pin cluster to one compatible Dgraph version; avoid mixed-version reads","Take regular backups (dgraph backup) and verify restores","Run badger verification after unclean shutdowns","Test schema/protobuf compatibility before custom data migrations"],"tags":["storage","badger","protobuf","corruption"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}