Hey there, we have an Order Routing Location Rule function on the cart.fulfillment-groups.location-rankings.generate.run target (API version 2026-01). This is its input query:
query Input {
cart {
cost {
totalAmount { amount }
}
}
fulfillmentGroups {
handle
inventoryLocationHandles
lines {
merchandise {
__typename
... on ProductVariant {
variantData: metafield(namespace: "<redacted>", key: "<redacted>") {
value
}
}
}
}
}
}
The rule needs the variant data on fulfillmentGroups.lines to rank the locations. But in the logs we can see runs where lines comes back as an empty array. Input:
{
"cart": {
"cost": {
"totalAmount": { "amount": "<non-zero>" }
}
},
"fulfillmentGroups": [
{
"handle": "1",
"inventoryLocationHandles": [
"<loc-1>", "<loc-2>", "<loc-3>",
"<loc-4>", "<loc-5>", "<loc-6>"
],
"lines": []
}
]
}
Output:
{ "operations": [] }
So the function has nothing to work with and can only stay silent, and the order gets routed as if the rule wasn’t there. The run still reports OK.
A few things make us think the payload itself is wrong rather than the cart simply being empty: it was well under the size limit so nothing was truncated, cart.cost.totalAmount is not zero, inventoryLocationHandles still comes through populated, and __typename is selected unconditionally so a line would appear in the array even if its merchandise weren’t a ProductVariant.
This looks like a platform bug to us, since the function can’t do its job without the data it asked for in the input query. Happy to share the invocation IDs and the full payloads in a private message.
Two things worth checking before treating it as a platform bug. First, the target is only partially supported on some surfaces: POS runs it only when the order ships to a customer, and order edits only for new items. If the empty-lines runs cluster on POS or order-edit checkouts, that points to degenerate input rather than truncation. Second, guard the silence: when lines comes back empty, return a fallback ranking of the inventoryLocationHandles instead of empty operations, so routing never silently ignores your rule.
Thanks, both useful points.
On the first one, I checked the support matrix and these runs aren’t on a
partially supported surface. Across the runs I’ve checked, this shows up fewer
than five times in seven days, and every one of them is the same shape: orders
created server side through the Admin API rather than a real checkout, so Create
Order API or Draft Order, both of which are listed as fully supported. Not POS,
and not order edits either, they’re new orders with their own IDs rather than
edits to the original. That said, if partially supported or unsupported surfaces
are expected to invoke the function with degenerate input rather than skipping
it, that would be very useful to have documented, because right now there’s no
way to tell the two apart from inside the function.
To be clear on truncation, I wasn’t claiming it. I mentioned the size limit only
to rule it out.
On the second one, I don’t think there’s a useful fallback available. With no
variant data there’s nothing to rank on. Ranking every candidate at rank 0 is
the same outcome as returning no operations, and any non uniform ranking would
be arbitrary, which is worse than staying silent, since the rule can run ahead
of Shopify’s own closest location step and would then override a sensible
default with noise. What I will do is alert on the empty lines case so it stops
being invisible, but I don’t think a function should invent a ranking to cover
for input it wasn’t given.
Your diagnosis looks solid - you’ve already ruled out the usual suspects (truncation, unsupported surfaces, empty cart), and the fact that it only shows up on Admin-API-created orders (Create Order / Draft Order) is a strong tell. That’s a real, repeatable pattern, not noise.
Realistically this isn’t something the community can fix. When a function asks for data in its input query and gets an empty array back on a supported surface, that’s a platform-side question only Shopify can answer - either it’s a bug, or those server-side order paths resolve line/merchandise data differently than a normal checkout and it just isn’t documented. Both are worth confirming, and neither is visible from inside the function. I’d escalate it directly with the invocation IDs and payloads you offered, rather than waiting on the thread. Partner/dev support or a bug report is the right channel, and having those same-shape examples ready will make it easy for them to trace.
Agree with your call on the fallback too - inventing a ranking to cover for missing input would just add noise ahead of Shopify’s default routing. Alerting on the empty-lines case so it’s not silent is the sensible move. Hope this helps 