hyperledger/fabric · error
proto: Marshal called with nil
Error message
proto: Marshal called with nil
What it means
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.
Source
Thrown at core/chaincode/lifecycle/serializer.go:56
}
type RangeableState interface {
GetStateRange(prefix string) (map[string][]byte, error)
}
type ReadRangeableState interface {
ReadableState
RangeableState
}
type Marshaler func(proto.Message) ([]byte, error)
func (m Marshaler) Marshal(msg proto.Message) ([]byte, error) {
if m != nil {
return m(msg)
}
if !msg.ProtoReflect().IsValid() {
return nil, errors.New("proto: Marshal called with nil")
}
return proto.Marshal(msg)
}
var ProtoMessageType = reflect.TypeFor[proto.Message]()
// Serializer is used to write structures into the db and to read them back out.
// Although it's unfortunate to write a custom serializer, rather than to use something
// pre-written, like protobuf or JSON, in order to produce precise readwrite sets which
// only perform state updates for keys which are actually updated (and not simply set
// to the same value again) custom serialization is required.
type Serializer struct {
// Marshaler, when nil uses the standard protobuf impl.
// Can be overridden for test.
Marshaler Marshaler
}
// SerializableChecks performs some boilerplate checks to make sure the given structureView on GitHub (pinned to 2736b63f8f)
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
Example fix
// before
var policy pb.ApplicationPolicy
bytes, err := m.Marshal(&policy) // invalid message
// after
policy := &pb.ApplicationPolicy{Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ChannelConfigPolicyReference: "admin"}}
bytes, err := m.Marshal(policy) Defensive patterns
Strategy: type-guard
Validate before calling
if msg == nil || !msg.ProtoReflect().IsValid() {
return nil, errors.New("message is nil/invalid before Marshal")
} Type guard
func isValidProto(msg proto.Message) bool { return msg != nil && msg.ProtoReflect().IsValid() } Try / catch
bytes, err := m.Marshal(msg)
if err != nil && strings.Contains(err.Error(), "Marshal called with nil") {
// initialize the message before retrying
} Prevention
- Initialize proto pointer fields before serialization
- Rely on Serialize's fieldValue.IsNil() branch rather than passing nil messages
- Check IsValid() on messages built dynamically
When it happens
Trigger: 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.
Common situations: Programmatic use of lifecycle serializer with structs whose proto pointer fields were never initialized; a nil EndorsementPolicy or ValidationParameter pointer reaching Serialize.
Related errors
- unsupported pointer type %v for field %s (must be proto)
- could not marshal field %s
- proto: Marshal called with nil
- error marshaling proposal
- failed to marshal args
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/39d25f04fb5ce929.
Report an issue: GitHub.