Hey @KyleG-Shopify, super thanks for digging into this! Here’s everything you need.
Routing Rules
Default Shopify routing, no customization:
- Minimize split shipments
- Stay within the destination market
- Ship from the closest location
Store Setup
- 2 locations:
- Toronto — Set as the Default Location. Serves only Toronto/Ontario. Has 1 unit of the product.
- Vancouver — Serves all of Canada. Has 2 units of the product.
- Default Location: Toronto (Settings → Locations)
- Shipping address: Toronto
- Payment status: Captured
- Fulfillment status: Unfulfilled, all fulfillment orders
OPEN
- All merchant-managed locations, no third-party fulfillment services
Why We Remove and Re-Add
Our app allows customers to modify their order quantities after checkout. When the quantity changes, Shopify needs to recalculate warehouse assignments and shipping rates. We found the cleanest way to let Shopify do this is to remove all existing line items and then re-add the new desired quantity — this forces Shopify’s routing engine to re-evaluate from scratch using the store’s routing rules.
We cannot do the removal and re-addition in a single edit session. If we try to orderEditBegin → orderEditSetQuantity(0) → orderEditAddVariant → orderEditCommit all in one go, Shopify returns a userErrors with “Order cannot be updated.” So we split it into separate sessions: one commit to remove, another commit to re-add.
When items are split across multiple warehouses, there’s an additional constraint — we can’t even remove from all warehouses in a single session. If we try to set both the Toronto line item and the Vancouver line item to 0 within one orderEditBegin → orderEditCommit, it also throws “Order cannot be updated.” So we have to remove from each warehouse in its own separate session: one commit per warehouse.
The Exact Sequence That Triggers the Bug
This only happens when you arrive at a split fulfillment through sequential order edits — not when you place a split order directly. Here’s the full sequence:
Step 1 — Customer checks out with 1 unit, shipping to Toronto.
Shopify assigns it to Toronto (closest, serves the destination, has stock).
Toronto: 0 available, 1 committed. Vancouver: 2 available.
Step 2 — Customer increases quantity to 3.
Since we can’t adjust and re-route in a single session (as explained above), we do two sessions:
Session 1 — Remove:
orderEditBegin → orderEditSetQuantity(quantity: 0, restock: true) → orderEditCommit
This removes the 1 unit from Toronto and restocks it. Commit returns clean, userErrors: []. Toronto goes back to 1 available.
Session 2 — Re-add:
orderEditBegin → orderEditAddVariant(quantity: 3) → orderEditCommit
Shopify’s routing engine kicks in. It needs to place 3 units. Toronto has 1, Vancouver has 2. No single location can fulfill all 3, so it splits: 1 from Toronto, 2 from Vancouver. This is correct — minimize split shipments can’t avoid a split here, so it distributes optimally.
Order state is now: 1 unit at Toronto, 2 units at Vancouver.
Step 3 — Customer decreases quantity to 2. This is where the bug happens.
We need to remove all 3 units and re-add 2. The items are split across Toronto and Vancouver. As explained above, we can’t remove from both warehouses in a single session — Shopify throws “Order cannot be updated.” So we remove from each warehouse in its own session:
Session 1 — Remove 1 unit from Toronto:
orderEditBegin → orderEditSetQuantity(quantity: 0, restock: true) → orderEditCommit
Toronto’s 1 unit restocks fine. Commit returns userErrors: []. ✓
Session 2 — Remove 2 units from Vancouver:
orderEditBegin → orderEditSetQuantity(quantity: 0, restock: true) → orderEditCommit
(The order of removal here matters. We remove in ascending quantity order — Toronto first (1 unit), Vancouver second (2 units). If there were a third warehouse with 3 units, we’d remove that last. We discovered through testing that removing in any other order causes Shopify to return “Order cannot be updated.” This ascending sequence is the only one that gets through without a lock error.)
Commit returns userErrors: [] — no error reported. But when you check Vancouver’s inventory after this, the 2 units are not restocked. They remain permanently stuck in “Committed” and never return to “Available.”
Session 3 — Re-add 2 units:
orderEditBegin → orderEditAddVariant(quantity: 2) → orderEditCommit
Because Vancouver’s inventory is now corrupted (2 units stuck in Committed), Shopify sees reduced available stock across the network and makes incorrect routing decisions.
What Doesn’t Trigger the Bug
If you place a fresh order directly with 3 units (so Shopify creates the split fulfillment of 1 from Toronto + 2 from Vancouver at checkout), and then immediately edit it down to 2, the restock works fine. Both locations restock correctly.
The bug only triggers when the split fulfillment was created through a sequential order edit — checkout with 1, then edit up to 3 (which creates the split), then edit down to 2 (which fails to restock).
Summary
- The
orderEditCommit response is always clean — userErrors: []. There is no error signal. The restock failure is completely silent.
- This is reproducible through the Admin UI as well. Edit the order manually, reduce the quantity, tick Restock, update — same result, inventory stays stuck in Committed.
- The Default Location (Toronto) being the same as the shipping destination may be relevant here — we’ve seen this be a factor in our testing.
Let me know if there’s any other information needed, happy to share!
Thanks again, Kyle!