This guide on batch stock reconciliation won't cancel is written for Indian SMEs, with code samples, ERPNext / Medusa recipes, and step-by-step fixes you can copy into a real project. You upgraded from ERPNext v14 to v15, and now you're cleaning up stock. You create a Stock Reconciliation to zero out an old batched item, submit it,. Then need to cancel it — and ERPNext refuses with "Serial No / Batch No are mandatory for Item". Worse, the reconciliation quietly produced two Serial and Batch Bundles instead of a single movement. The same action worked fine on v14. This is a migration-seam regression, it is specific to stock created before the upgrade,. This guide shows how to tell whether you're exposed and reconcile the stock without stranding an entry you can't reverse. This guide on batch stock reconciliation won't cancel is written for Indian SMEs, with code samples, ERPNext / Medusa recipes, and step-by-step fixes you can copy into a real project.
New to how v15 tracks batches?
v15 replaced the old inline batch/serial fields with the Serial and Batch Bundle document. If that model is unfamiliar, ERPNext serial and batch tracking explains it — this post assumes it and focuses on the migration fault.
The most dangerous stock entries are the ones you can post but can't cancel, because you only discover the trap after it's in the ledger. I am Manoj, ERPNext and Frappe implementation lead at Mith Tech in Bengaluru, and this one bites businesses in the first stock cleanup after a v15 upgrade.
What actually breaks
In v15, ERPNext tracks serialised. Batched movements through the Serial and Batch Bundle document — a structured record that links each ledger entry to the specific batches and serial numbers it moved. Stock created natively under v15 carries these links. Stock that existed before the upgrade does not: its Stock Ledger Entries were written under v14's inline model and were migrated forward without a bundle behind them.
The regression in #38796 surfaces when you reconcile that migrated stock to zero. Instead of posting a single movement, the reconciliation generates two Serial and Batch Bundles — one outward with a negative quantity, one inward with a positive quantity. The net quantity is correct, so nothing looks wrong at first. The trap springs when you try to cancel: ERPNext builds the cancellation from the old Stock Ledger Entry. Which has no bundle to reference, and validation rejects it with "Serial No / Batch No are mandatory for Item". You are left with a submitted reconciliation you cannot reverse.
PR #38754 addresses the cancel path, and the batch-quantity handling in reconciliation was refined further on the later v15 line — the linked bundle is now cancelled and the Current Serial and Batch Bundle field cleared when the quantity reaches zero. On v14 none of this arose, because there was no bundle layer to desynchronise.
Toggle whether the stock predates your v15 upgrade, whether you are zeroing it, and whether you are on an early v15 release to see if you are exposed to the reconciliation cancel bug.
Test cancel-ability before any bulk reconciliation
The single most useful thing you can do is reconcile one migrated batch item to zero on a staging copy and immediately try to cancel it. If the cancel fails, you now know not to run the same operation across your register. A reconciliation you cannot cancel is a worse position than the stock discrepancy you were trying to fix.
Five symptoms around v15 batch reconciliation
The Serial and Batch Bundle system introduced several distinct reconciliation edge cases in early v15. They look similar and have different fixes.
Select the batch-reconciliation symptom you are seeing to identify which tracking issue it belongs to and what the fix path is.
The two that share the #38796 root cause are the un-cancellable reconciliation and the double-bundle structure — they are the same fault seen from two angles. The others are separate: an auto-fetch reading the wrong existing quantity for items that mix plain-batch and bundle transactions (#42702), a miscalculated valuation difference (#40168), and serial validation failing across multiple batches. All of them argue for the same thing: be on a current release before you reconcile migrated batched stock, and never trust a bulk run you haven't tested on one item.
How do you fix it?
Copy-paste the one-item exposure test, the bench upgrade sequence, the unblock path for an already-stuck reconciliation, and the habits that keep migrated stock safe.
Find your exposed items
The exposed population is batch-tracked items that held stock before the v14→v15 upgrade and still carry ledger entries from that era. This is a property of your migration, not something that happens at random, so you can enumerate it up front rather than discovering it item by item. The data migration guide covers how to reason about what carried over.
Test cancel-ability on one item
On a staging copy, zero one migrated batch item with a Stock Reconciliation and immediately try to cancel it. A failure with "Serial No / Batch No are mandatory" confirms you are on an unpatched release and exposed. Stop there — do not repeat it across the register.
Upgrade before the bulk run
Back up with files, update the erpnext app on the version-15 branch to a release carrying PR #38754 and the later batch fixes, and re-run the one-item test on staging. The cancel must now succeed and clear the Current Serial and Batch Bundle field before you reconcile in bulk.
Reconcile from a count, per batch
Set reconciled quantities from a physical count rather than the auto-fetch — the auto-fetch is unreliable for items that mix plain-batch and bundle history (#42702). For items that are both batch- and serial-tracked across multiple batches, reconcile per batch rather than in one combined entry. Our stock reconciliation guide covers the mechanics.
Verify cancel-ability after each entry
After each migrated-item reconciliation, confirm both the Stock Ledger balance and that the entry can be cancelled before moving on. Verifying cancel-ability is the check that would have caught the original problem, so make it routine rather than something you only do when something looks wrong.
When the upgrade owner and the stock owner are different people
The person doing the post-upgrade stock cleanup is usually in stores or inventory. The person who ran the upgrade is in IT and has moved on to the next thing. So the stores user meets the un-cancellable reconciliation alone, weeks after go-live, and has no reason to connect it to the upgrade — from their seat it is just ERPNext behaving strangely on old stock.
The fix is to make the migration seam an explicit part of the go-live plan rather than something discovered later. Post-upgrade stock reconciliation of batched items belongs on the cutover checklist, done on a patched release, tested on one item first, and owned jointly by whoever ran the upgrade and whoever owns inventory. The reconciliation of migrated batched stock is a migration task, not a routine stores task, and treating it as routine is what lets it strand an entry nobody can reverse.
Draft policy for your IT and inventory leads to ratify. Stock Reconciliation of batch- or serial-tracked items that held stock before the v15 upgrade is performed only on a release confirmed to carry the Serial and Batch Bundle reconciliation fixes, and only after cancel-ability has been tested on a single item on staging. Reconciled quantities are set from a physical count, not the auto-fetch. Every migrated-stock reconciliation is verified for both ledger balance and cancel-ability before the next. No Serial and Batch Bundle is edited or deleted at the database to work around a cancel failure. Confirm the target release against your changelog before this enters the cutover runbook.
Should you choose Upgrade first, or reconcile now?
| You have migrated batched stock to clean up in bulk | The item was created natively under v15 |
| Your one-item test failed to cancel | Your one-item test cancelled cleanly |
| You are on an early v15 release near v15.6 | You are on a current v15 point release |
| The stock cleanup is part of a go-live cutover | This is routine reconciliation of native v15 stock |
| You mix batch and serial tracking across batches | Single-batch, quantity-only reconciliation |
How do you At a glance — quick reference?
| Aspect | What to know |
|---|---|
| When to use Batch Stock Reconciliation Won't Cancel | Standard fit for the common case; review edge cases against the table. |
| Typical effort | 1–4 hours for a small team; longer with custom data or multi-entity setups. |
| Main risk | Skipping reconciliation or running before the data is clean. |
| What to do next | Run the steps below, then verify against the checklist. |
FAQ: what do people ask most?
+Why can't I cancel a Stock Reconciliation in ERPNext v15?
+Why did zeroing old stock create two Serial and Batch Bundles?
On affected early-v15 releases, reconciling pre-v15 batched stock to zero posts an outward bundle with negative quantity and an inward bundle with positive quantity instead of a single Stock Entry. The net is correct but the structure is what later breaks the cancel. The fixed flow cancels the linked bundle and clears the field when quantity reaches zero.
+Which items are affected by this bug?
Batch-tracked (and serial-tracked) items that held stock before your v14→v15 upgrade. Their ledger entries predate the Serial and Batch Bundle system, so they carry no bundle link. Stock created natively under v15 is not affected because it has proper bundles from the start.
+Did this work on ERPNext v14?
Yes. v14 had no Serial and Batch Bundle layer, so there was nothing to desynchronise — the reconciliation and its cancellation behaved normally. The problem is specific to the v15 bundle system interacting with data migrated from before it existed, which is why it is a regression rather than a long-standing bug.
+How do I fix a reconciliation that's already stuck and won't cancel?
Do not hand-edit the bundles at the database. Take a full backup, upgrade a staging copy restored from it, confirm the stuck reconciliation now cancels there, then upgrade production and cancel it. Re-do the stock zeroing correctly on the patched release. The stuck entry is a reason to upgrade, not to edit the ledger by hand.
+What happens if we keep reconciling migrated stock on the old release?
You accumulate submitted reconciliations you cannot cancel, each leaving the ledger half-reversed if you try. Every one becomes a manual cleanup after you eventually upgrade, and some may need a physical recount to establish the truth. Testing one item and upgrading first is far cheaper than unwinding a register full of stuck entries.
What related issues might you also hit?
- Reconciliation auto-fetching the wrong existing quantity for mixed batch/bundle items (#42702).
- Wrong difference amount on reconciliation with Serial and Batch bundle (#40168).
- ERPNext blocks backdated stock entries after a reconciliation — another reconciliation-timing trap on the stock side.
- ERPNext data migration guide — reasoning about what carries across an upgrade.
What is the bottom line?
This is a narrow fault with a wide blast radius: it only touches stock migrated from v14, but it hides until you try to cancel, by which point it is in the ledger. Put post-upgrade batch reconciliation on the cutover checklist, be on a patched release before you run it, and test cancel-ability on one item before the rest. That turns a register full of stuck entries into a routine cleanup.
Post-upgrade stock cleanup throwing errors you can't cancel?
We map your migrated batched stock, get you onto a release that reconciles it cleanly, and run the cutover cleanup so you don't strand entries you can't reverse.