Partial MSI reindex can leave products missing from inventory_stock_<stock_id> after a failed index write
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 357
- Forks
- 262
- PR merge metrics
- No merged PRs in 30d
Description
### Preconditions (*)
1. Magento Open Source 2.4.9 with MSI enabled.
2. MySQL/InnoDB and a non-default stock (for example, stock ID 2).
3. A product assigned to a source that belongs to that stock, with an existing row in `inventory_stock_2`.
### Steps to reproduce (*)
1. Trigger a partial MSI reindex for a SKU, for example by changing its source-item quantity or salable status.
2. Cause `IndexDataFiller::saveIndex()` to fail after `IndexDataFiller::cleanIndex()` succeeds. This occurs in production when concurrent MSI index writes cause a MySQL deadlock, such as:
```text
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
```
3. Query the stock index table after the failed reindex:
```sql
SELECT * FROM inventory_stock_2 WHERE sku = '';
```
4. Run a full inventory reindex and repeat the query.
### Expected result (*)
1. A partial reindex should be atomic: if replacement index data cannot be written, the existing `inventory_stock_` rows must remain unchanged.
2. A failed reindex must not leave the affected SKU absent from the stock index table.
### Actual result (*)
1. `IndexDataFiller` calls `cleanIndex()` (DELETE) and `saveIndex()` (INSERT/UPSERT) without a transaction. When the write fails after the delete, the delete remains committed.
2. The affected SKU is missing from `inventory_stock_2` until a full reindex recreates it. This can produce an incorrect salability/stock status and can cause subsequent reservation salability updates to fail because no current stock-index row exists.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the MSI partial reindex path into IndexDataFiller::cleanIndex() and IndexDataFiller::saveIndex(), focusing on how the DELETE and replacement write are persisted. Reproduce the failed-write scenario with a non-default stock and verify that the existing inventory_stock_ row remains present after the failure, while a successful partial reindex still updates it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- mysql, php
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100