Inventory troubleshooting
422 scan_required when receiving stock
Section titled “422 scan_required when receiving stock”Symptom: a receipt, or a count that raises the quantity, is refused — from the web, the assistant, the CLI or MCP.
Stock enters Inventory only by reading a code of the item. A person’s
receive, or an adjust with a positive quantity, must carry
source_reference: "scan:<code>", and that code must belong to the item being
received. The CSV opening-stock import (apply_import) is refused for the same
reason.
- In the web, receive from the Scan screen: scan the item’s barcode (a reader or the phone camera) and apply the queue.
- The goods have no code yet: attach the barcode already printed on them, or generate and print an internal code, then scan it. Attaching codes is an administrator verb.
- From a script, the code must be a real code of that item. A code of another item, or an unknown one, is refused the same way.
Integrations are exempt; a connected system brings its own evidence.
409 label_already_received
Section titled “409 label_already_received”Every item label Inventory prints carries its own serial in the QR, and a scanned receipt records those serials. The same sticker cannot bring stock in twice — neither scanned twice in one receipt nor received again later.
New stock needs new labels. If the earlier receipt was a mistake, reverse it in full: that frees its stickers for another receipt. Labels printed before per-sticker serials existed, and shelf labels, are not checked.
An order cannot be picked: 409 insufficient_stock
Section titled “An order cannot be picked: 409 insufficient_stock”Symptom: the order is confirmed, its line shows it is waiting, and fulfilling it is refused.
Inventory takes an order even when the stock is not there yet — the order
waits instead of being lost. A line can only leave the shelf once the units
are physically on hand. The line’s waiting says how many are missing, and the
position shows the same shortfall as backordered.
Receive the goods when they arrive, and the pick goes through. Never record a receipt or an adjustment for stock that did not arrive to unblock an order: the ledger would then promise units nobody can pick.
If another order confirmed earlier needs the same units, the line also shows
claimed and claimed_by. That is advice about who should go first, never a
block.
409 integration_owned on Confirm, Release or Dispatch
Section titled “409 integration_owned on Confirm, Release or Dispatch”The order was created by a connected app — usually Commerce — and only that app may confirm, release or dispatch it. This applies to administrators too: confirming or cancelling a shop’s order from the warehouse would leave the shop with a sale it never changed.
- Confirm or cancel the order in the app that owns it.
- The warehouse can still fulfill it once it is confirmed.
- If that app’s integration has been revoked, an administrator can release the hold (but not confirm it).
409 conflict — “only an unexpired held reservation can be confirmed”
Section titled “409 conflict — “only an unexpired held reservation can be confirmed””The hold passed its expires_at and expired: its stock went back to
available. A hold expires on the next read or command in the workspace after
its deadline, so it can disappear from the list the moment you open it.
Create the order again. Confirmed orders never expire, so confirm a hand-written order before its hold runs out.
409 conflict — “operation_key was already used with different input”
Section titled “409 conflict — “operation_key was already used with different input””Every command carries an operation_key, and a key stands for one logical
change. Sending it again with the same input returns the original answer — that
is how a retry after a timeout stays safe. Sending it with any other value
changed is refused.
Use a new key for a new change, and reuse a key only to retry exactly the same request.
403 when a member tries something
Section titled “403 when a member tries something”| Code | Why |
|---|---|
admin_required |
The operation needs a workspace owner or admin: settings, locations, stock owners, integrations, Shopify, and — for a member without Inventory roles — catalog edits, codes, adjustments, owner and condition changes, and reversals |
permission_required |
The member has Inventory product roles and none of them grants the named permission |
forbidden_scope |
An integration credential lacks the scope, or the stock belongs to an owner it is not granted |
A member with product roles is restricted to what the roles grant — even verbs
an unrestricted member could run, such as receive. Grant the permission in a
role, or ask an administrator. Configuration can never be granted through a
role. See Roles and permissions.
401 from a script or connected system
Section titled “401 from a script or connected system”unknown_bearer_scheme— the bearer is neither an identity PAT (idn_pat_…) nor an Inventory credential (inv_key_…). The tokendst login’s browser flow stores is a destesi-api key; mint a PAT at account.destesi.io/me/tokens and log in withdst login --token-file -.missing_workspace_header— a PAT needsX-Destesi-Workspace: <slug>. The CLI sends it fromdst workspace switch <slug>or--workspace.invalid_integration— theinv_key_credential is unknown or was revoked. Inventory keeps only its hash, so it cannot be shown again: create a new integration and store its credential.
404 not_found on an id you can see elsewhere
Section titled “404 not_found on an id you can see elsewhere”An id from another workspace, and one outside an integration’s stock owners,
both answer 404 — the API never confirms that someone else’s record exists.
An integration also sees only the orders it created. Check the workspace, or
the integration’s owner_ids with get_context.
A stock move is refused
Section titled “A stock move is refused”| Message | Cause |
|---|---|
insufficient available stock |
issue, transfer, owner, condition and resize move only available stock; units promised to orders stay put |
adjustment would consume committed stock |
A downward count cannot take units already promised to orders. Release or fulfill them first |
location is archived |
An archived location refuses receipts and upward counts |
destination location is archived |
Transfers cannot land in an archived location |
item is archived |
Archived items cannot be received or reserved |
quantity exceeds precision or range |
More decimals than the item’s scale allows |
incompatible unit |
The unit is neither the base unit, an item pack label, nor a standard unit of the same dimension |
A size change is refused
Section titled “A size change is refused”A resize moves stock only one size down, into a variant of the same
product with every other attribute equal. It is refused when:
- the target is not the next smaller size (two steps, or a step up);
- the product has no variant in that size — create the variant first;
- the shop has no category that wears sizes. Set one in Commerce, or in Inventory’s Settings → Shop category when Commerce has none;
- scanned, the old tag is not a code of the source variant, or the new tag not
a code of the target. A scanned change is one garment: quantity
1.
503 market_unavailable means Commerce did not answer with the shop category
in time. Retry.
Archiving a location is refused
Section titled “Archiving a location is refused”A location cannot be archived while any of its stock is held or allocated to an order. Fulfill or release those orders, then archive it. Stock still on the shelf can be moved out afterwards; an archived location allows evacuation.
409 integration_managed when revoking
Section titled “409 integration_managed when revoking”Commerce and Relay each get one integration per workspace, managed by the suite. Revoking it would stop that product’s catalog, so it is refused. Credentials you created yourself can be revoked.
Shopify publishing does not write anything
Section titled “Shopify publishing does not write anything”Check get_shopify_push_status (or Settings → Shopify) first.
| Code or status | What to do |
|---|---|
no_catalog_source |
Link a Shopify store first |
store_not_connected / store_not_active |
Connect the store, or fix its connection, in Connect |
push_disabled |
Publishing is off until an administrator enables it |
no_location_mapping |
Pair at least one Inventory location with a Shopify location. Only paired locations are published |
listed_quantity_needs_one_location |
Items carry a listed quantity, which has no location. Pair exactly one location, or clear the listed quantities |
needs_reauth |
The Shopify connection was granted before Destesi could write to the store. Reconnect it in Connect |
| An item in drift | Shopify’s quantity changed outside Destesi — usually a sale Inventory has not heard about. Inventory will not overwrite it; reconcile, then sync |
A product with no publication price is published as a draft; set one with
set_shopify_price. Quarantined, damaged and other owners’ stock is never
published.
Loading a Shopify store did not add stock
Section titled “Loading a Shopify store did not add stock”That is by design. A load creates or updates items, and Shopify’s quantity becomes each item’s listed quantity — what the store advertises, not what is on your shelf. On-hand stock stays at zero until it is received by scanning. Gift cards and variants Shopify does not track or ship are skipped.
Alerts never arrive
Section titled “Alerts never arrive”- The chat still reads pending. The person must press Start in Telegram from the link the web showed. The link works on one device.
- The chat does not hear that category. Check its categories in Settings → Telegram; an empty list mutes it.
- Stock was already low. A low-stock alert fires when available stock
crosses the line, not while it stays under it. Only items counted in
eachget the low-stock alert; others (grams, litres) alert only when they sell out. - Connect is not wired to this deployment. Pairing answers
503 connect_unconfigured.
WhatsApp is never used for Inventory alerts.
The assistant is off or forgets an approval
Section titled “The assistant is off or forgets an approval”503 chat_disabled— no AI model is selected for Inventory in the suite’s admin console. The forms and the API work without it.404 approval_missing— a paused operation waits 10 minutes for your answer, and a restart of the Inventory API clears it. Ask again; nothing was applied.