hyperledger/fabric · error

could not marshal field %s

Error message

could not marshal field %s

What it means

During Serialize, a non-nil proto pointer field is marshaled with the configured Marshaler; if proto marshaling fails (invalid message, marshaler misconfigured), the error is wrapped as 'could not marshal field <name>'. Unlike index 552, this occurs only for non-nil fields whose contents are invalid.

Source

Thrown at core/chaincode/lifecycle/serializer.go:159

		fieldName := value.Type().Field(i).Name
		fieldValue := value.Field(i)

		keyName := FieldKey(namespace, name, fieldName)

		stateData := &lb.StateData{}
		switch fieldValue.Kind() {
		case reflect.String:
			stateData.Type = &lb.StateData_String_{String_: fieldValue.String()}
		case reflect.Int64:
			stateData.Type = &lb.StateData_Int64{Int64: fieldValue.Int()}
		case reflect.Slice:
			stateData.Type = &lb.StateData_Bytes{Bytes: fieldValue.Bytes()}
		case reflect.Pointer:
			var bin []byte
			if !fieldValue.IsNil() {
				bin, err = s.Marshaler.Marshal(fieldValue.Interface().(proto.Message))
				if err != nil {
					return errors.Wrapf(err, "could not marshal field %s", fieldName)
				}
			}
			stateData.Type = &lb.StateData_Bytes{Bytes: bin}
			// Note, other field kinds and bad types have already been checked by SerializableChecks
		}

		marshaledFieldValue, err := s.Marshaler.Marshal(stateData)
		if err != nil {
			return errors.WithMessagef(err, "could not marshal value for key %s", keyName)
		}

		if existingValue, ok := existingKeys[keyName]; !ok || !bytes.Equal(existingValue, marshaledFieldValue) {
			err := state.PutState(keyName, marshaledFieldValue)
			if err != nil {
				return errors.WithMessage(err, "could not write key into state")
			}
		}
		delete(existingKeys, keyName)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fully initialize the proto message including its oneof before calling Serialize
  2. Validate the message with msg.ProtoReflect().IsValid() / proto checks before serializing
  3. Inspect the wrapped inner error (errors.Unwrap) to find the underlying marshal failure
  4. If a custom Marshaler is installed, verify it handles the message type correctly

Example fix

// before
policy := &pb.ApplicationPolicy{} // oneof unset
s.Serialize(state, metadata, &Def{Policy: policy})
// after
policy := &pb.ApplicationPolicy{Type: &pb.ApplicationPolicy_Policy{Policy: &pb.SignaturePolicyEnvelope{Version: 0}}}
s.Serialize(state, metadata, &Def{Policy: policy})
Defensive patterns

Strategy: try-catch

Validate before calling

if fieldMsg != nil && !fieldMsg.ProtoReflect().IsValid() {
  return errors.New("proto field invalid before Serialize")
}

Type guard

func isMarshalableProto(msg proto.Message) bool { return msg != nil && msg.ProtoReflect().IsValid() }

Try / catch

err := s.Serialize(state, metadata, def)
if err != nil && strings.Contains(err.Error(), "could not marshal field") {
  var inner error
  if e, ok := err.(interface{ Unwrap() error }); ok { inner = e.Unwrap() }
  // inspect inner marshal error, fix the named field's proto message
}

Prevention

When it happens

Trigger: Serialize on a struct whose proto pointer field is non-nil but internally invalid (e.g. a oneof unset / invalid required data) so s.Marshaler.Marshal returns an error.

Common situations: Constructing an EndorsementPolicy/ApplicationPolicy message incorrectly (empty oneof) before committing a chaincode definition; custom Marshaler functions returning errors for certain message types.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/fbaa222e2fb04371. Report an issue: GitHub.