hyperledger/fabric · critical
proto: Marshal called with nil
Error message
proto: Marshal called with nil
What it means
MarshalOrPanic serializes a protobuf message and panics on failure. Before marshaling it checks pb.ProtoReflect().IsValid(); a message holding a nil concrete pointer (typed nil) is invalid, and calling proto.Marshal on it panics inside the protobuf runtime. The library converts that into an explicit panic with the message 'proto: Marshal called with nil' so the failure is attributable to this helper.
Source
Thrown at protoutil/commonutils.go:24
package protoutil
import (
"crypto/rand"
"fmt"
cb "github.com/hyperledger/fabric-protos-go-apiv2/common"
"github.com/hyperledger/fabric/internal/pkg/identity"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)
// MarshalOrPanic serializes a protobuf message and panics if this
// operation fails
func MarshalOrPanic(pb proto.Message) []byte {
if !pb.ProtoReflect().IsValid() {
panic(errors.New("proto: Marshal called with nil"))
}
data, err := proto.Marshal(pb)
if err != nil {
panic(err)
}
return data
}
// Marshal serializes a protobuf message.
func Marshal(pb proto.Message) ([]byte, error) {
if !pb.ProtoReflect().IsValid() {
return nil, errors.New("proto: Marshal called with nil")
}
return proto.Marshal(pb)
}
// CreateNonceOrPanic generates a nonce using the common/crypto package
// and panics if this operation fails.View on GitHub (pinned to 2736b63f8f)
Solutions
- Check the variable passed to MarshalOrPanic for nil before the call: if pb == nil { ... }.
- Audit the function that produced the message — handle its error return instead of ignoring it.
- Switch to protoutil.Marshal (non-panicking) at call sites where nil is plausible.
- Add a guard/helper that logs and returns an error instead of panicking in production paths.
Example fix
// before
raw := protoutil.MarshalOrPanic(env) // env may be nil
// after
if env == nil {
return errors.New("envelope is nil")
}
raw, err := protoutil.Marshal(env)
if err != nil { return err } Defensive patterns
Strategy: type-guard
Validate before calling
if env == nil {
return errors.New("cannot marshal nil envelope")
}
raw := protoutil.MarshalOrPanic(env) Type guard
func isValidMessage(pb proto.Message) bool {
return pb != nil && pb.ProtoReflect().IsValid()
} Try / catch
func safeMarshal(pb proto.Message) (raw []byte, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("marshal panicked: %v", r)
}
}()
raw = protoutil.MarshalOrPanic(pb)
return
} Prevention
- Never pass typed-nil pointers to MarshalOrPanic.
- Always check errors from constructors before marshaling their result.
- Prefer protoutil.Marshal in code paths where nil is plausible.
- Keep panics out of production request paths; reserve OrPanic helpers for init/genesis code.
When it happens
Trigger: Calling MarshalOrPanic with a typed-nil message, e.g. protoutil.MarshalOrPanic((*cb.Envelope)(nil)) or a function that returned a nil *Envelope with a non-nil error ignored by the caller.
Common situations: serializeIdentity or block-building helpers receiving results of failed constructors whose errors were ignored; zero-value struct pointers in config-generation code; refactors where a factory started returning nil on an error path.
Related errors
- err
- error marshaling Response: proto: Marshal called with nil
- error marshaling ChaincodeEvent: proto: Marshal called with
- error marshaling ChaincodeActionPayload: proto: Marshal call
- error marshaling ProposalResponse: proto: Marshal called wit
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/9bd8ccf8ef767e80.
Report an issue: GitHub.