hyperledger/fabric · error
receiver %T.%s does not return an error as its second return
Error message
receiver %T.%s does not return an error as its second return value
What it means
Dispatch requires the second of the method's two return values to implement the error interface so failures can be propagated to the caller. This error is thrown when the second return type does not implement error.
Source
Thrown at core/dispatcher/dispatcher.go:52
if method.Type().NumIn() != 1 {
return nil, errors.Errorf("receiver %T.%s has %d parameters but expected 1", receiver, methodName, method.Type().NumIn())
}
inputType := method.Type().In(0)
if inputType.Kind() != reflect.Pointer {
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)
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Change the second return value to the standard error interface: func (s *Svc) Do(req *pb.Req) (*pb.Resp, error).
- If a custom error type is kept, add an Error() string method so it implements error.
- Move custom failure details into the response proto message and return a plain error instead.
Example fix
// before
func (s *Svc) Do(req *pb.Req) (*pb.Resp, *FailureInfo) { ... }
// after
func (s *Svc) Do(req *pb.Req) (*pb.Resp, error) {
...
if failed {
return nil, fmt.Errorf("failed: %v", info)
}
return resp, nil
} Defensive patterns
Strategy: validation
Validate before calling
func validateSecondReturnIsError(receiver any, methodName string) error {
m := reflect.ValueOf(receiver).MethodByName(methodName)
if !m.IsValid() || m.Type().NumOut() != 2 {
return fmt.Errorf("method %s missing or wrong shape", methodName)
}
if !m.Type().Out(1).Implements(reflect.TypeFor[error]()) {
return fmt.Errorf("method %s second return does not implement error", methodName)
}
return nil
} Type guard
func secondReturnIsError(receiver any, methodName string) bool {
m := reflect.ValueOf(receiver).MethodByName(methodName)
return m.IsValid() && m.Type().NumOut() >= 2 &&
m.Type().Out(1).Implements(reflect.TypeFor[error]())
} Prevention
- Always end handler signatures with a plain error return value.
- If using custom error types, assert they implement error: var _ error = (*MyErr)(nil) — or simply return error.
- Run a startup reflection check over all dispatched methods to catch signature drift early.
When it happens
Trigger: Calling Dispatch (via Invoke) on a method like func (s *Svc) Do(req *pb.Req) (*pb.Resp, string) or (*pb.Resp, *MyErrStruct) where the second return type lacks an Error() string method.
Common situations: Handlers returning custom error structs that do not implement error; returning a status value or error code string directly; accidental type or order swaps after refactoring.
Related errors
- receiver %T.%s has %d parameters but expected 1
- receiver %T.%s does not accept a pointer as its argument
- receiver %T.%s returns %d values but expected 2
- receiver %T.%s does not return a an implementor of proto.Mes
- message of type %s unknown
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/b837075a851d3d7d.
Report an issue: GitHub.