hyperledger/fabric · error

receiver %T.%s does not accept a proto.Message as its argume

Error message

receiver %T.%s does not accept a proto.Message as its argument, it is '%T'

What it means

Dispatch uses reflection to invoke a chaincode-receiver method whose input argument must implement proto.Message. After creating a new instance of the declared input type, it asserts that instance to proto.Message; if the assertion fails the method's input type is not a valid protobuf message, so the call cannot be dispatched.

Source

Thrown at core/dispatcher/dispatcher.go:58

		return nil, errors.Errorf("receiver %T.%s does not accept a pointer as its argument", receiver, methodName)
	}

	if method.Type().NumOut() != 2 {
		return nil, errors.Errorf("receiver %T.%s returns %d values but expected 2", receiver, methodName, method.Type().NumOut())
	}

	if !method.Type().Out(0).Implements(reflect.TypeFor[proto.Message]()) {
		return nil, errors.Errorf("receiver %T.%s does not return a an implementor of proto.Message as its first return value", receiver, methodName)
	}

	if !method.Type().Out(1).Implements(reflect.TypeFor[error]()) {
		return nil, errors.Errorf("receiver %T.%s does not return an error as its second return value", receiver, methodName)
	}

	inputValue := reflect.New(inputType.Elem())
	inputMsg, ok := inputValue.Interface().(proto.Message)
	if !ok {
		return nil, errors.Errorf("receiver %T.%s does not accept a proto.Message as its argument, it is '%T'", receiver, methodName, inputValue.Interface())
	}

	err := d.Protobuf.Unmarshal(inputBytes, inputMsg)
	if err != nil {
		return nil, errors.WithMessagef(err, "could not decode input arg for %T.%s", receiver, methodName)
	}

	outputVals := method.Call([]reflect.Value{inputValue})

	if !outputVals[1].IsNil() {
		return nil, outputVals[1].Interface().(error)
	}

	if outputVals[0].IsNil() {
		return nil, errors.Errorf("receiver %T.%s returned (nil, nil) which is not allowed", receiver, methodName)
	}

	outputMsg := outputVals[0].Interface().(proto.Message)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Change the receiver method's input type to a generated protobuf message type that implements proto.Message
  2. Regenerate protobuf code with protoc-gen-go so the struct implements the proto.Message interface (ProtoReflect method)
  3. Ensure only one protobuf module version is imported so the interface assertion succeeds

Example fix

// before
func (r *Receiver) DoThing(ctx context.Context, in *MyPlainStruct) (proto.Message, error)
// after
func (r *Receiver) DoThing(ctx context.Context, in *pb.MyThingRequest) (proto.Message, error)
Defensive patterns

Strategy: validation

Validate before calling

var _ proto.Message = (*pb.MyThingRequest)(nil) // compile-time check before registering
func validInput(m interface{}) bool {
    _, ok := m.(proto.Message)
    return ok
}

Type guard

func isProtoMessage(v interface{}) bool {
    _, ok := v.(proto.Message)
    return ok
}

Prevention

When it happens

Trigger: Registering/invoke-dispatching to a receiver method whose input parameter is a Go struct that does not embed/implement proto.Message (e.g. a plain struct or pointer-to-wrong-type), then calling Invoke on it.

Common situations: Hand-written chaincode receivers using custom argument structs instead of generated protobuf types; proto package version mismatches (google.golang.org/protobuf vs github.com/golang/protobuf) so the type no longer satisfies proto.Message; typos in generated code regeneration.

Related errors


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