hyperledger/fabric · error

receiver %T.%s returned (nil, nil) which is not allowed

Error message

receiver %T.%s returned (nil, nil) which is not allowed

What it means

After invoking the receiver method, Dispatch requires the first return value (the output proto.Message) to be non-nil when the error return is nil. A receiver returning (nil, nil) gives the dispatcher nothing to marshal, so it is rejected as a programming error.

Source

Thrown at core/dispatcher/dispatcher.go:73

	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)

	resultBytes, err := d.Protobuf.Marshal(outputMsg)
	if err != nil {
		return nil, errors.WithMessagef(err, "failed to marshal result for %T.%s", receiver, methodName)
	}

	return resultBytes, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Return a valid (non-nil) proto.Message from the receiver on success paths
  2. If no payload is expected, return an empty message instance (e.g. &pb.EmptyResponse{}) instead of nil
  3. Return a non-nil error instead of nil,nil for the no-result case

Example fix

// before
func (r *Receiver) DoThing(ctx context.Context, in *pb.Req) (proto.Message, error) {
    return nil, nil
}
// after
func (r *Receiver) DoThing(ctx context.Context, in *pb.Req) (proto.Message, error) {
    return &pb.EmptyResponse{}, nil
}
Defensive patterns

Strategy: type-guard

Validate before calling

// receiver-side unit test
out, err := recv.DoThing(ctx, req)
if err == nil && out == nil { t.Fatal("receiver returned (nil, nil)") }

Type guard

func isNilProto(m proto.Message) bool {
    return m == nil || !m.ProtoReflect().IsValid()
}

Prevention

When it happens

Trigger: A receiver method invoked via Invoke/Dispatch returns (nil, nil) — e.g. it does `return nil, nil` on a success path or forgets to set its response message.

Common situations: Chaincode handler that returns early without building a response proto; methods with optional responses that were written as plain Go functions returning nil.

Related errors


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