Quick answer

If products show as sold out on the storefront with add-to-cart disabled, while the admin and Admin API report them as available, the configuration is probably fine. Inventory settings, markets and shipping zones are dead ends in this case.

The cause we traced was a stale availability index on Shopify's side. Any write to a delivery profile rebuilds it: we made a trivial temporary change to one shipping zone, and about twenty seconds later every country could buy again, including ones we never touched. Test per country with the localization cookie rather than in your own browser.

This one is worth writing down because the symptom points at the wrong thing. Everything you would normally check comes back healthy, so people spend days re-checking it. Here is what we found on a store we audit, what turned out to be irrelevant, and the single action that fixed it.

A full, brightly lit warehouse interior seen through the closed steel shutter of a shopfront
Full shelves, closed door. The stock was never the problem.

01 · Symptom

Available in the admin, sold out on the storefront.

On the store in question, every product was purchasable from some countries and sold out from others. Add-to-cart was disabled on the storefront, and posting to the cart endpoint directly returned an error saying the product was already sold out.

Meanwhile the Admin API reported the variant as available for sale, contextual pricing returned a valid price for the affected countries, and inventory was not even being tracked. The two halves of Shopify disagreed with each other, which is what makes this so disorienting.

It had been happening for over a month before anyone noticed, because the owner and the team were all in countries where the store worked fine.

02 · Dead ends

Do not spend days on these.

Every one of these was correct, and checking them proved nothing:

  • Inventory tracking was off, so the product could never run out.
  • The inventory policy allowed selling when out of stock.
  • The Admin API reported the variant as available for sale.
  • Contextual pricing returned a price for the affected countries.
  • Markets included every country, and the shop was set to ship to all of them.
  • Shipping zones covered the affected countries with active rates.

If your checks look like this list, you are not missing a setting. The configuration is not the problem.

03 · Cause

A stale availability index.

Shopify decides whether a product can be bought from a given country by consulting a derived index built from markets, shipping and delivery configuration. That index can end up stale: correct settings, wrong conclusion, and nothing in the admin shows it.

It is a rare failure, and it is invisible precisely because every input to it looks right. The only visible artefact is the disagreement between what the Admin API says and what the storefront does.

04 · Fix

Write once to a delivery profile.

Any write to a delivery profile causes the index to rebuild. In our case we made a trivial, temporary change to the countries in one shipping zone through the Admin GraphQL API, using deliveryProfileUpdate.

Around twenty seconds later every country could buy again, including countries we had not touched. That is what proves the fix came from the rebuild rather than from the change itself. We then reverted the zone to exactly what it had been, and availability stayed correct.

One implementation note that cost us time: the location group identifier this mutation expects is the delivery location group, not the profile location group, which has no identifier of its own.

05 · Testing

Test it by country, not by eye.

Your browser's location changes what you see, so looking at the store proves nothing about other countries. Request the product as a specific country by setting the localization cookie, and read the availability field on the product JSON endpoint, or post to the cart endpoint and watch for the error.

Space the requests out. Hammering the endpoint gets you rate-limited, and a rate-limit response is easy to misread as another failure.

Then do it for every country you sell to, not just the two you thought were broken. In our case the affected set was much wider than reported, simply because nobody in the affected countries had bothered to complain.

Quick check

Before you commit.

  • The admin and the storefront genuinely disagree with each other.
  • Inventory tracking, policy and markets have all been confirmed correct.
  • You tested availability per country, not in your own browser.
  • You wrote once to a delivery profile and waited a minute.
  • You re-tested every country, not only the reported ones.
  • Any temporary change to shipping zones was reverted afterwards.

When every input is right, suspect the derived data.

Most storefront bugs are configuration. A few are the platform's own derived state, and those are only found by noticing that two parts of the same system disagree. That disagreement is the signal.

Questions

Questions people ask.

Why do my Shopify products say sold out when I have stock?

The common causes are inventory tracking with zero quantity, a policy that prevents overselling, or the product not being available in the market the visitor is browsing from. If all of those are correct and the admin still disagrees with the storefront, the availability index may be stale.

Why is my Shopify store sold out only in some countries?

Availability is decided per country from markets, shipping and delivery configuration. If those all include the country and the product is still unavailable there, the derived availability index is likely stale rather than the settings being wrong.

How do I force Shopify to refresh product availability?

Write once to a delivery profile through the Admin API. A trivial change to a shipping zone triggers a rebuild of the availability index, after which countries you never touched become purchasable again. Revert the temporary change afterwards; availability stays correct.

Want this applied to your store?Let’s build something different.
Start a project