Blocking at the cart, and whether the shopper sees why

A validation rule can stop the Add to cart button as well as checkout. The block itself always works. Whether your message appears on the page is decided by your theme, and themes disagree. Here is how to find out which kind yours is, and what to hand a theme developer if it is the wrong kind.

Last updated 24 August 2026

What the cart setting does

Every validation rule applies at checkout. That screen is Shopify's own, so your message is shown there on every store and in every theme. A rule can also be switched on for the cart, with Also stop this in the cart, before checkout in the rule builder. It then runs on Add to cart and on quantity changes too, before the shopper ever reaches checkout.

The app leaves that setting off by default. This page is why.

The block always happens. The message may not.

When a cart-enforced rule matches, Shopify refuses the request on its own servers. The item is not added and the quantity does not change. There is nothing a shopper can do about that, and no theme can switch it off.

Showing your message is a separate job, and it belongs to the theme. Shopify hands the theme the message and moves on; a theme that was never written to look for it displays nothing. Shopify's own wording is that errors from validation functions "are exposed to the Storefront API's Cart object, in themes that use the cart template and during checkout" — exposed to the theme, which then has to put them on the page.

We have watched both outcomes, on the same rule and the same store. On Shopify's Dawn theme the message appeared in full, in red, above the Add to cart button. On the generated theme a fresh development store ships with, nothing appeared at all: the button did nothing, the quantity stepper snapped back to where it was, and there was no error anywhere on the page. Same rule, same refusal, two different experiences for the shopper.

If you are not sure, leave the cart setting off. Checkout shows your message on every theme, because Shopify draws that screen and your theme does not.

Check your own theme in 30 seconds

Your message appeared — you are done, and you can leave the setting on. Nothing happened at all — your theme is swallowing the message, so either turn the cart setting off and let the block land at checkout, or send the next section to whoever looks after your theme. Either is fine. The rule is enforced either way; only the explanation is missing.

For theme developers

The rest of this page is for whoever edits the theme's code. Nothing here changes in the app.

What Shopify sends back

A cart-enforced validation is applied by Shopify, not by the theme, so it arrives as an error on the Ajax Cart API. We have measured /cart/add.js and /cart/change.js: both answer with HTTP 422 and this body. Every cart mutation runs the same validation, so the snippet below watches /cart/update.js too — that one we have not measured.

{
  "status": 422,
  "message": "Orders over $500 are placed by your account manager - please call us.",
  "description": "Orders over $500 are placed by your account manager - please call us."
}

Three fields, and that is the whole body: status, message, description. For a validation block, message and description both carry the merchant's own text. For Shopify's built-in cart errors — sold out, no such variant — message is the fixed string Cart Error and description carries the sentence a shopper should read. Read description first, fall back to message, and you have covered both.

Branch on the response not being ok rather than on a number. Shopify's reference documents 404 for an unknown variant; the store we measured answered 422 for that same call.

A plain GET /cart is not affected — validations do not run on it, so a cart filled before the rule went live renders normally and is stopped at checkout.

A snippet, if the theme has nowhere to put the message

Shopify publishes no canonical handler for this, and themes disagree about where a cart error belongs, so this is deliberately small. It watches the cart requests the page already makes and prints the message; it changes nothing else. Paste it into layout/theme.liquid wrapped in a script tag, immediately before the closing body tag, and change MOUNT to a selector in your own theme.

(function () {
  // Where the message is inserted. Change this to a selector in your theme.
  var MOUNT = 'form[action*="/cart/add"]';
  var original = window.fetch;
  if (typeof original !== 'function') return;

  window.fetch = function () {
    return original.apply(this, arguments).then(function (res) {
      if (!res || res.ok) return res;
      if (!/\/cart\/(add|change|update)/.test(res.url || '')) return res;
      res.clone().json()
        .then(function (body) { show(body?.description || body?.message); })
        .catch(function () {});
      return res;
    });
  };

  function show(text) {
    if (!text) return;
    var host = document.querySelector(MOUNT);
    if (!host) return;
    var el = document.getElementById('cart-rule-message');
    if (!el) {
      el = document.createElement('div');
      el.id = 'cart-rule-message';
      el.setAttribute('role', 'alert');
      host.prepend(el);
    }
    el.textContent = text;
  }
})();

Style it with #cart-rule-message in the theme's own CSS. Two things it does not cover: a theme that uses XMLHttpRequest instead of fetch, and a theme that already prints something of its own — check for that before you add a second message.

Shopify's documentation