{"record":{"id":"39d25f04fb5ce929","repo":"hyperledger/fabric","slug":"proto-marshal-called-with-nil","errorCode":null,"errorMessage":"proto: Marshal called with nil","messagePattern":"proto: Marshal called with nil","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/lifecycle/serializer.go","lineNumber":56,"sourceCode":"}\n\ntype RangeableState interface {\n\tGetStateRange(prefix string) (map[string][]byte, error)\n}\n\ntype ReadRangeableState interface {\n\tReadableState\n\tRangeableState\n}\n\ntype Marshaler func(proto.Message) ([]byte, error)\n\nfunc (m Marshaler) Marshal(msg proto.Message) ([]byte, error) {\n\tif m != nil {\n\t\treturn m(msg)\n\t}\n\tif !msg.ProtoReflect().IsValid() {\n\t\treturn nil, errors.New(\"proto: Marshal called with nil\")\n\t}\n\treturn proto.Marshal(msg)\n}\n\nvar ProtoMessageType = reflect.TypeFor[proto.Message]()\n\n// Serializer is used to write structures into the db and to read them back out.\n// Although it's unfortunate to write a custom serializer, rather than to use something\n// pre-written, like protobuf or JSON, in order to produce precise readwrite sets which\n// only perform state updates for keys which are actually updated (and not simply set\n// to the same value again) custom serialization is required.\ntype Serializer struct {\n\t// Marshaler, when nil uses the standard protobuf impl.\n\t// Can be overridden for test.\n\tMarshaler Marshaler\n}\n\n// SerializableChecks performs some boilerplate checks to make sure the given structure","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/lifecycle/serializer.go#L38-L74","documentation":"The lifecycle serializer's Marshaler wrapper checks whether the proto message is valid (non-nil) before calling proto.Marshal; calling Marshal with a nil/invalid proto.Message yields this sentinel error instead of panicking inside the protobuf library.","triggerScenarios":"Serialize or metadata/serialization checks in _lifecycle invoking Marshaler.Marshal with a nil proto.Message pointer (e.g. a nil *lb.ChaincodeDefinition embedded field), typically due to a nil field in the struct being serialized.","commonSituations":"Programmatic use of lifecycle serializer with structs whose proto pointer fields were never initialized; a nil EndorsementPolicy or ValidationParameter pointer reaching Serialize.","solutions":["Initialize the proto pointer field before serialization (allocate the concrete message struct)","Check field validity with msg.ProtoReflect().IsValid() before calling Marshal","Skip/omit nil proto fields — Serialize already guards with fieldValue.IsNil(), so ensure that path is used rather than passing nil directly"],"exampleFix":"// before\nvar policy pb.ApplicationPolicy\nbytes, err := m.Marshal(&policy) // invalid message\n// after\npolicy := &pb.ApplicationPolicy{Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ChannelConfigPolicyReference: \"admin\"}}\nbytes, err := m.Marshal(policy)","handlingStrategy":"type-guard","validationCode":"if msg == nil || !msg.ProtoReflect().IsValid() {\n  return nil, errors.New(\"message is nil/invalid before Marshal\")\n}","typeGuard":"func isValidProto(msg proto.Message) bool { return msg != nil && msg.ProtoReflect().IsValid() }","tryCatchPattern":"bytes, err := m.Marshal(msg)\nif err != nil && strings.Contains(err.Error(), \"Marshal called with nil\") {\n  // initialize the message before retrying\n}","preventionTips":["Initialize proto pointer fields before serialization","Rely on Serialize's fieldValue.IsNil() branch rather than passing nil messages","Check IsValid() on messages built dynamically"],"tags":["fabric","protobuf","nil-pointer","serialization"],"backgroundTag":"proto-marshal-nil","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}