Wrong data
Wrong price, wrong stock, missing product. Commerce holds a copy of what the ERP published, so these are nearly always a question about what arrived and when — not about a calculation.
The shape of every one of these tickets
flowchart LR
ERP["ERP<br/>the source"] --> P["Integration push"]
P --> DB[("Commerce<br/>database")]
DB --> C["In-process<br/>cache"]
DB --> IX["Search<br/>index"]
C --> UI["What the<br/>customer sees"]
IX --> UI
style ERP fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#1e1b4b
style P fill:#e8f4f9,stroke:#00415a,stroke-width:2px,color:#002230
style DB fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px,color:#2e1065
style C fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px,color:#2e1065
style IX fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px,color:#2e1065
style UI fill:#fffbeb,stroke:#b45309,stroke-width:2px,color:#451a03
Four places the truth can differ, and they narrow the problem completely:
| Compare | If they differ | Then |
|---|---|---|
| ERP vs Commerce database | The push has not arrived, or was rejected | Upstream. Ask for the push to be re-sent |
| Database vs what the customer sees | A cache, or the search index, is stale | Clear the cache, or wait for the index |
| Both agree, customer still disputes | Not a data problem | Check what they are comparing against — a quoted price, an old catalogue |
Always establish which of these you have before acting. Clearing a cache when the data never arrived wastes the call.
Wrong price
Prices come from pricing rules pushed by the ERP. The usual causes, in order:
A stale rule that should have expired. This is the most common, and it is caused by a real design asymmetry: pricing rules are the one push that does not delete what is absent. Every other feed is a snapshot — send it without a row and the row is removed. Pricing is not. A rule is only retired by giving it an end date.
So a rule the ERP no longer sends is still live in Commerce. If a price looks like an old price, this is almost certainly why.
A missing rule, leaving the product to fall back to a less specific rule or to no price at all. A product with no determinable price cannot be added to a basket.
Quantity breaks. A rule applies from a minimum quantity. A price that "only goes wrong for large orders" is a break doing its job.
Dates. Rules carry validity windows. A price that changed at midnight changed because a window did.
Note
The price a customer pays is not the product's unit price from the catalogue feed. That field is a list price. Pricing rules decide what is charged, and promotions and bonus products can change it again.
Wrong stock
Stock is a snapshot, not a promise. It reflects the last inventory push, and nothing is held until checkout reserves it.
| Report | Likely cause |
|---|---|
| Quantity is out of date | The push has not run, or the SKU was not in it |
| A location has vanished | Inventory pushes are snapshots — a location absent from a push is removed |
| Available is lower than expected | Reservations. Both in-flight checkouts and placed orders deduct |
| Stayed low long after checkouts finished | A committed reservation — see below |
Availability is on hand minus live reservations, so reservations are the usual explanation for a figure that looks too low. Which kind matters:
- A held reservation belongs to a checkout in progress and expires on its own, after 30 minutes by default. Wait, and it clears.
- A committed reservation belongs to a placed order and has no expiry. It clears only when the ERP's next stock push says it has absorbed that order — released in the same transaction as the new stock figures.
So availability that stays low points at an order the ERP has not yet acknowledged. That is a question for the ERP feed, not for Commerce, and the reservation is doing its job by holding the line until the push arrives.
Full mechanism, including why the release has to be atomic with the stock update: Inventory lifecycle.
Missing or wrong product
| Symptom | Cause |
|---|---|
| Not in the back office either | Never pushed. Upstream problem |
| In the back office, not in search | The index has not caught up — wait five minutes. Browse still works |
| Visible to some customers only | Entitlement — see Access |
| Visible to nobody | The blocked flag |
| A field is empty that was sent | Possibly not projected into the index — see below |
The search index trap
Search runs against a separate index, populated from a database view by an indexer that runs every five minutes. Two consequences:
A change is not instant. Up to five minutes passes before a corrected product is searchable, so it is right in the database and wrong in search in between. Browse and direct lookup read the database, so a product correct in browse and wrong in search is normal and needs no action.
Some fields never reach the index at all. A column can exist on the product, and be a field in the index, and still be empty on every document — because the view feeding the indexer does not project it. Nothing errors.
Warning
Sleeve length and fabric type are exactly this. Both are accepted, stored, and never indexed. They cannot be searched or filtered on. A ticket asking why filtering by fabric returns nothing is not a bug in the data — the field never arrives.
Clearing a cache
Commerce caches in process, and the back office can clear one named cache or all of them, with hit and miss statistics per cache.
Reach for it when the database is right and the customer sees something else. It is safe — the next request repopulates — but it is not a general fix. If the database is wrong, clearing the cache changes nothing and costs you the time.
Statistics are also a diagnosis in themselves: a cache with almost no hits is not helping, and one with constant invalidations is being written to more than it is read.