Shopify's inventorySetQuantities Mutation Now Requires an Idempotency Key — Here's Why Your Inventory Sync Started Failing
If a custom app, 3PL integration, or Shopify Flow automation writes inventory through the inventorySetQuantities mutation and started throwing invalid-value errors sometime after API version 2026-04 went live, the cause is almost always the same: the idempotency key that was optional in 2026-01 became mandatory in 2026-04. Here's what changed, why Shopify made it required, and the exact mutation shape that fixes it.
If your store's inventory sync — a 3PL connector, a WMS integration, a custom app, or a Shopify Flow workflow using the "Send Admin API request" action — started throwing errors sometime after Shopify's API version 2026-04 went live on April 1, 2026, and the message is some variant of "Variable $input of type InventorySetQuantitiesInput! was provided invalid value," you're not looking at a bug in your integration. You're looking at a mutation that quietly changed its contract, and the error message doesn't say what actually broke. Shopify Community threads describing this exact symptom in Flow's Admin API action step, and a separate Shopify Developer Community report of the mutation "breaking" after a schema refresh, both trace back to the same root cause once you dig past the generic validation message.
What actually changed in the mutation
The inventorySetQuantities mutation went through two related changes on Shopify's own developer changelog, and it's easy to only catch one of them:
- Compare-and-swap redesign (effective November 14, 2025, API version 2026-01): the legacy
compareQuantityandignoreCompareQuantityfields were deprecated in favor of a singlechangeFromQuantityfield. Pass an integer to enable a compare-and-set check against the currently persisted quantity, or passnullto skip it. Shopify's changelog is explicit that this step alone "isn't considered breaking," because omittingchangeFromQuantityfalls back to the legacy fields — but that fallback isn't permanent. - Idempotency key requirement (API version 2026-04): the mutation supported an optional idempotency key via an
@idempotentdirective starting in 2026-01. As of 2026-04, that key is required. A request that omits it fails input validation before the mutation logic even runs — which is exactly the generic "provided invalid value" error developers are reporting, because GraphQL's variable-validation layer doesn't explain which specific requirement was missed.
Both 2026-04 and the newer 2026-07 version are live now, and Shopify runs a minimum 12-month support window per version with at least nine months of overlap — so if your integration is pinned to an older API version string in its request headers, you may still be on the deprecated shape today. That's worth checking before you assume the mutation itself is broken.
Why Shopify made the idempotency key mandatory
This isn't an arbitrary tightening. inventorySetQuantities writes an absolute quantity value, not a delta — which is exactly the kind of write where a duplicate execution (a retried request after a timeout, a webhook firing twice, a queue redelivering a job) can silently overwrite a more recent value with a stale one. An idempotency key lets Shopify recognize "this is the same logical write being retried" and return the original result instead of applying it twice. Shopify's own mutation documentation is direct about the risk the compare-and-swap fields exist to manage in the first place: "Opting out of the compareQuantity check can lead to inaccurate inventory quantities if multiple requests are made concurrently." Making the idempotency key mandatory closes the other half of that same class of bug — accidental duplication, not just concurrent overwrite.
Diagnose whether this is your problem
- Check the API version your integration sends — in a custom app, this is the version in your REST/GraphQL endpoint URL or the
X-Shopify-Api-Versionbehavior of your client library; in Shopify Flow's "Send Admin API request" action, it's whatever version that action step is configured against. - Search your mutation string for
@idempotent. If it isn't there and you're callinginventorySetQuantitieson 2026-04 or later, this is almost certainly your failure. - If you're using a GraphQL client generated from an introspected schema (for example
graphql-codegenwith@shopify/api-codegen-preset), be aware that Shopify's schema proxy excludes deprecated fields from introspection by default. A Shopify Developer Community thread on this exact mutation traces a "field is not defined by type" error back to a codegen refresh that silently strippedcompareQuantityandignoreCompareQuantityout of the generated types, even though the store's pinned API version still required them. If you regenerate types and integrations that touch this mutation suddenly won't compile, addincludeDeprecated: trueto your schema loader's introspection config before assuming the fields were actually removed on Shopify's side.
The fix: the current mutation shape
This is what a correctly-formed call looks like against 2026-04 and later. The idempotency key is passed as a separate GraphQL variable and attached via the directive — it is not a field inside input:
mutation inventorySetQuantities(
$input: InventorySetQuantitiesInput!
$idempotencyKey: String!
) {
inventorySetQuantities(input: $input) @idempotent(key: $idempotencyKey) {
inventoryAdjustmentGroup {
createdAt
reason
changes {
name
delta
quantityAfterChange
}
}
userErrors {
field
message
}
}
}
And the corresponding variables, using the current field names rather than the deprecated compare-and-swap pair:
{
"input": {
"name": "available",
"reason": "correction",
"referenceDocumentUri": "wms://sync-job/48213",
"quantities": [
{
"inventoryItemId": "gid://shopify/InventoryItem/48861327",
"locationId": "gid://shopify/Location/62518819",
"quantity": 42,
"changeFromQuantity": 39
}
]
},
"idempotencyKey": "wms-sync-48213-loc62518819-item48861327"
}
Two things matter about that idempotency key value: it needs to be deterministic per logical operation, not random per HTTP attempt — generate it once from something stable in your own system (a job ID, a source document ID, a composite of item and location) and reuse the identical value across retries of that same logical write. A fresh UUID on every retry defeats the entire point; Shopify will treat each retry as a brand-new write instead of recognizing the duplicate.
If you're calling this from Shopify Flow
Flow's "Send Admin API request" action sends whatever raw GraphQL you give it, so the fix is the same mutation shape above — but Flow doesn't give you a convenient way to generate a stable per-execution key from inside the workflow editor itself. One documented workaround from a Shopify Community thread on this exact failure: the merchant abandoned the Flow-based approach entirely and moved the sync logic into a small custom app, using an external scheduler to trigger it, specifically because Flow's action step made it awkward to manage the idempotency key correctly. That's a legitimate tradeoff to weigh rather than a dead end — if your inventory sync is simple and infrequent, a workflow-based key (built from the Flow run's own trigger data, like an order ID or a timestamp truncated to the sync interval) is enough. If it's high-frequency or multi-location, a small dedicated app gives you real control over key generation and retry logic, which is worth the extra maintenance.
One more decision worth revisiting while you're in here
inventorySetQuantities is meant for systems that act as the source of truth for a given inventory quantity — a WMS or 3PL that owns "available" count outright. If your integration is actually applying relative changes (an order shipped, a return restocked, a manual correction of ±N units) rather than asserting an absolute count, inventoryAdjustQuantities is the more correct mutation and sidesteps the compare-and-swap question entirely, since deltas don't have the same "which value is authoritative" ambiguity that absolute sets do. Migrating off deprecated compare-and-swap fields is a reasonable moment to double-check you're using the right mutation for what your system is actually doing, not just patching the one you already had.
Migration checklist
- Confirm the API version your integration targets — anything on 2026-04 or later requires the idempotency key; earlier supported versions (down to 2025-07) still accept the legacy fields.
- Add the
@idempotent(key: $idempotencyKey)directive to everyinventorySetQuantitiescall, sourced from a deterministic value tied to the logical operation, not generated fresh per retry. - Replace
compareQuantity/ignoreCompareQuantitywithchangeFromQuantitybefore Shopify removes the deprecated fields outright. - If you use schema codegen, set
includeDeprecated: trueduring any transition period where you need both old and new fields visible in generated types. - Re-confirm whether
inventorySetQuantitiesis even the right mutation for what you're doing, versus the delta-basedinventoryAdjustQuantities.
This is the same category of problem covered in our audit of the JSON metafield 128KB limit and the Shopify Scripts deprecation migration — a platform-level API change that ships correctly documented but surfaces to the merchant as a generic, unhelpful error deep inside an app or automation nobody's looked at in months. Inventory sync failures are worse than most, because a silently stuck sync doesn't throw a visible storefront error — it just means your available counts drift from reality until someone notices a stockout or an overselling complaint.
Code Kaarigari builds and maintains Shopify inventory integrations, custom apps, and Flow automations, and audits existing ones for exactly this class of quiet breakage before it costs a store a stockout or a channel desync. See our Shopify app development and API integration services, or contact Code Kaarigari if an inventory sync has started failing and you need the root cause found quickly.
Sources reviewed
- Shopify Developer Changelog: Improved compare and swap inventory updates for the inventorySetQuantities mutation
- Shopify GraphQL Admin API: inventorySetQuantities mutation reference
- Shopify GraphQL Admin API: inventoryAdjustQuantities mutation reference
- Shopify Developer Docs: About Shopify API versioning
- Shopify Community: Flow inventorySetQuantities 2026-01
- Shopify Developer Community: inventorySetQuantities mutation broken