Require shipping method in Commerce order flow I have a page, almost exactly the default Commerce shipping.html template and flow. With just the default shipping method (Free), the user can simply click through without being required to select a shipping method. I've found how to use a Business Logic plugin to address required fields for the address/billing section, but there doesn't seem to be an event I can hook to so I can yell and provide a flash error message if the user clicks "Select Shipping Method" without actually selecting one.

I know I can redirect back to the shipping method page on the payment page by checking the cart (ex: {% if not cart.shippingMethod %}...) but this doesn't provide a flash error unless I use some hacky method like a GET string error message.

Is there an event I can hook to I'm not finding in the docs that will let me force the choice of a shipping method? Or a setting in the plugin I'm missing?

Edit 

So I'm close, here's my event code that isn't working as I expect it to (did I tell you I'm new to Craft yet?):

    craft()-&gt;on( 'commerce_orders.onSaveOrder', function ( Event $event ) {

        $order = $event-&gt;params['order'];

        if(craft()-&gt;request-&gt;getPost('validateShipping')){

            // add error to shippingMethod and see if we can get it
            $order-&gt;addError('shippingMethod',Craft::t('Please select a shipping option.'));
            $event-&gt;performAction = false;

            // pass a flash for testing 
            craft()-&gt;userSession-&gt;setFlash('error', 'No shipping elected');
        }
    });


So this moves on to the payment page and doesn't return to the shipping page with the added error. However, I am able to retrieve the set flash message on the payment page but {{ dump(cart.getErrors()) }} results in an empty array, so either the error is not attached to the cart properly in my event, or it is lost for some reason.

Edit 

I see I'm getting some up views; If anyone can still help I'd appreciate it. I have yet to get this working as per the only answer, and would love to know what I'm doing wrong in my Craft Commerce event.
Ok, so shipping is not a necessity for a Commerce site (e.g. think about  e.g. digital downloads - shipping is not relevant here) - so Commerce does not force you to set a shipping method on an order.  

It's up to you to work out how and where you need to do this, if you do.

A lot (most,even) of it is often best tackled at the front end via your flow and some JS and/or general form validation stuff - you don't allow the user to proceed/submit if they have not chosen a method when you need them to.  We actually do it all, pretty much, in this end of things.

In addition, you CAN use any Commerce event you choose:
https://craftcommerce.com/docs/events-reference

...to add some extra validation (as you have with the address fields).  But it really depends on your precise checkout flow as to how you'd implement this.

For example, if your shipping page is POSTing to the Commerce controller updateCart when it submits, you could perhaps listen to:
https://craftcommerce.com/docs/events-reference#commerce_orders.onsaveorder

...and in that validate a shipping method is set (of course your order is saved many times during a commerce process so you should e.g. POST some other variable to check in there if you should actually trigger this validation).

&lt;input type="hidden" name="validateShipping" value="true"&gt;

And then in your event handler

if(craft()-&gt;request-&gt;getPost('validateShipping')){ ... validation here }

If there is an error, then to add the error you'd add it to the model you retrieved as an event parameter:

$order-&gt;addError('shippingMethod','No shipping method supplied!');

..and to set a flash message

craft()-&gt;userSession-&gt;setFlash('error', 'No shipping selected');

....but there are MANY possible ways you can implement this (e.g. no server side validation at all, if you can handle it all at the front end) -> the key thing is to really understand your checkout flow (and all the many ways users can travel through it) - quite thoroughly BEFORE you start implement the actual validation you need.