Skip to content
What a Void Undoes

I voided the document and the report still shows it: what a void undoes

“I voided the document and the report still shows it” — nearly always, nothing is broken: a void is not a delete, it posts a second set of entries in the opposite direction and keeps the document, so a report that lists movements still shows the original beside its reversal.

You voided the document. The screen says VOID. And the stock movement report still shows the quantity, or the cashbook still shows the money, or the ledger still shows both legs.

A void is not a delete and it is not a rewind. It is a second set of postings in the opposite direction, plus a short list of things that get removed outright, plus a shorter list of things that were never designed to come back — and each of those three behaves differently in a report. Knowing which is which is the difference between a five-minute check and an afternoon.

This page is the companion to How work actually runs, which traces one Finalise end to end. This one traces one Void, and the headline is the asymmetry between them: Finalise fans out to thirty-two subscribed processors. Void fans out to ten.

Fifteen minutes, nothing to configure. It applies to every document in the platform, because they are all the same record.

Four different ways to unwind a document, and only one of them is a void

Before anything else, make sure you want a void. The platform has four separate operations here and they take different code paths from the same screen.

You want toThe operationWhat it doesComes back?
Fix a mistake on something not yet finalEdit the draftNothing has posted yet, so nothing has to be undonen/a
Take a finalised document back to editableUndo to DraftReturns it to Draft and releases the knock-offs it was holding — and only those; one subscriber, not tenYou can re-finalise it, but what it already posted is not posted again — see below
Throw away something that should never have existedDiscardMarks it discarded and releases its knock-offs and contrasNo
Cancel a finalised document that really happened, and keep the trailVoidPosts the reversals below, with a reason, and keeps the documentNo
Correct a finalised document you are not allowed to voidA credit note, return or refund noteA new document with its own number and its own postingsIt is not an undo at all

A void is the one you want when the document was genuinely raised and genuinely has to be cancelled: a keyed-twice invoice, a cash bill rung up on the wrong till, a payment voucher to the wrong supplier. It keeps the document, its number and its history, and records who voided it and why — the void reason you type is stored on the document, and the whole before-and-after is written to the audit trail in the same call.

A void cannot be undone. There is no un-void. The only route back from a voided document is to key a new one, and it will have a new number.

What actually happens when you press it

Three things happen while you wait, and everything else happens afterwards.

While you wait, BigLedger (1) runs the refusal checks below and stops dead if any of them fires, (2) sets the document’s posting status to VOID and stores your reason, and (3) drops one row into your tenant’s job queue.

That is the whole synchronous part. The reversals have not started.

Then the fan-out. That single queued job is a primary processor, and when a worker picks it up it looks up which secondary processors are subscribed to it and queues one job for each. This is the same publish-subscribe machinery Finalise uses, and the subscription list is the thing worth knowing:

SubscriberWhat it undoes
Journal postingWrites an opposite journal
TaxReverses the tax transactions behind it
InventoryWrites negating stock movements and replays costing forward
CashbookRemoves the cashbook lines and un-matches the bank statement
Knock-off open queueGives the source order its outstanding quantity back — while knock-off from that kind of order is still enabled for the company
AR/AP contraUnpicks the settlements and restores both documents’ balances
Membership pointsRemoves the lots the document earned, but not the points from the balance the till shows, and returns no redeemed points (see Points Setup)
Entity spending limitReleases the customer’s consumed credit
Cash transferUnwinds the cashbook side of an internal transfer
Warehouse pick/pack queueRemoves the document from the picking queue

Ten. Finalise has thirty-two, and the twenty-two without a void counterpart are not an oversight in every case — several of them could not be undone even in principle. But they are the reason a void can look incomplete when it is finished. The section What a void will not do names the ones that matter.

Which of the ten run on your tenant, and where the two lists differ

Which of those ten run on your tenant is a subscription, exactly as it is for Finalise — a row in your own database naming the trigger template, not a code path. A subscription you do not have is a reversal that never happens, and no screen lists which ones you have.

The thing worth knowing is the gap between the two lists. Posting a journal on Finalise and reversing a journal on Void are two separate subscriptions, and nothing provisions them together. Holding the first is no guarantee of the second — not for the journal, not for stock, not for the cash book, not for loyalty points, and not for the quantity knock-off that reopens a sales order line. Settlements are the odd one out, because there is no Finalise-side subscription to compare against: a contra is written by the applet’s own request, not by a subscription. The void-side reversal is a subscription like all the others, and where it is missing a voided receipt leaves every invoice it paid still reading paid.

Where one of these is missing, the button still works. The document still goes to VOID, the audit trail is still written, and the journal is still POSTED — because there is nobody subscribed to unpost it. No message says so. The thirty-second check below is how you find out which kind of tenant you are on, and one voided test document answers it for good.

That shape is not hypothetical. A document sitting at VOID whose journal, cash book or inventory posting status still reads POSTED is exactly what it leaves behind. Some of those are a job that failed and some are a subscriber that was never there, and nothing in the product separates the two for you on a single document. Trace Document does not: it reads the document and then looks for the artefacts — the journal, the reversal journal, the cash book line, the shadow document, the open knock-off queue row — and it never touches a job record at all, so a job that threw and a subscriber that was never wired come back as the same red missing.

What separates them is repetition, not inspection. A subscriber that is not wired is missing on every document of that type, which is why the thirty-second check below, run once on a deliberate test document, settles it for the whole tenant. A job that failed is missing on this document and nowhere else, and Resolve puts it right.

A void is slower to take effect than a Finalise, and this is measurable

Finalise inserts its queue row and immediately hands the primary processor to a worker thread, so the work usually starts before the HTTP response reaches your browser. The void path only inserts the row. It waits for the next tenant pacemaker tick to be picked up.

So the first thing to do when a report still shows a voided document is nothing at all: refresh in a minute. “Stuck” is the customer’s own word for this, and it almost always means queued.

The three shapes of undo, and why reports disagree about them

This is the part that decides what you see on a screen, and it is not visible anywhere on the screen.

Shape 1 — reversed: a second, opposite entry, and the original stays

The journal. Voiding does not touch the journal that was posted. It reads that journal, swaps every line’s debit and credit, keeps the GL code, branch, profit centre, project, segment and sub-ledger exactly as they were, and posts it as a new journal. The account nets to zero. Both journals are in the ledger, and both are supposed to be — that is what an audit trail is.

So: your account detail will show two entries where you expected none. That is correct. Add them up.

Two things about that reversal are easy to miss.

It carries the original document’s transaction date. Only the posting timestamp is today. Void a January invoice in March and January moves — the reversal lands in January, not in March. If January has been reported, signed off or filed, you have just changed a period you had finished. This is deliberate (an accountant reversing a document wants the reversal where the document was, not smeared into an unrelated month), and it is the single most expensive surprise on this page. Check the document’s date before you void it, not after.

Only one journal is reversed. The reversal reads a journal for the document and reverses that one. A document that produced more than one journal header — and a foreign-currency document with a separate gain/loss posting is the obvious case — will not have the others reversed by this path. If your account is left with one leg standing after a void, this is the first thing to check, and it is the mechanism behind the desk’s “void reversal journal unbalanced” reports.

Tax follows the same shape, with one condition: the tax reversal runs only if the document’s journal posted. Tax follows the journal, not the document. A document that finalised but never produced a journal has nothing for the tax reversal to do, and it will quietly do nothing.

Shape 2 — negated: an opposite movement, and the original stays

Inventory. The void rebuilds the document’s stock movements, negates each quantity, stamps each one with the transaction code VOID, and inserts them as new rows in the stock ledger. The original movements stay exactly where they were.

This is the answer to the loudest symptom in the whole void family — “voided stock adjustment still showing in stock movement report”. A movement report shows movements, and a void makes a movement. Both rows are real, both are supposed to be there, and the two net to zero. Your stock balance is right; your stock movement report has two lines where you expected none. Check the balance, not the movement list.

Then, per negating line, three more jobs are queued:

  • costing is replayed forward from the movement immediately before the one being undone, so every later line’s moving average is recomputed — which is why a margin you looked at yesterday can move today;
  • brought-forward and carried-forward balances are recalculated for the periods after it;
  • the current stock balance is refreshed, including serial numbers, bins and batches.

And the document’s serial numbers are unlocked — released back to available. That is usually what you wanted, and it is worth knowing it happens, because it is also how a serial that “should have been sold” becomes sellable again.

One condition governs all of it: the negation only happens if the document actually posted to inventory. A document whose inventory posting never ran has nothing to negate, and the void will mark it voided without writing a single stock row. That is the “posting_inventory null after void stock adjustment” shape, and the check below will show it to you.

Shape 3 — removed: the row is taken away, not reversed

Four things are deleted rather than reversed, and this is why the cashbook and the AR/AP screens behave differently from the ledger after a void.

Cashbook lines are removed, not reversed. No opposite cashbook entry is written; the lines are marked deleted. And the removal is careful about the bank reconciliation: in one transaction it adds each matched amount back onto the bank statement line’s open amount, deletes the reconciliation links, and then removes the cashbook line.

Read that consequence slowly, because it reaches into a month you may have closed: voiding a document that was already reconciled puts its bank statement line back on your unmatched list. The reconciliation you signed off is now one line short of balanced. That is the design working — the alternative is a reconciliation matched to a transaction that no longer exists — but nobody tells you it happened.

Note also what the stored reconciliation header does not do: it does not re-derive itself. See Everything is matched to zero and the reconciliation still won’t tally.

Settlements (contras) are removed, and both sides are recalculated. Every contra the voided document takes part in is deleted, and then the outstanding balance is recomputed for both documents in each one. Void a receipt voucher and the invoices it paid go back to outstanding — that is the intended behaviour and it happens inside the same job, not on a schedule. It works from the other side too: void an invoice and the receipt that paid it becomes an unapplied credit again. One thing in this step is a deletion where you might expect a reversal: if a contra was cross-currency, the exchange-difference journal it posted is deleted outright, not reversed — so a forex gain or loss booked by a settlement leaves the ledger without a trace when the settlement goes.

Knock-off queue rows are removed, which is how a sales order gets its outstanding quantity back when the invoice raised from it is voided. That give-back has one condition, and it is the same for a void, an Undo to Draft, a discarded draft and a line removed and saved: the company must still have a knock-off pair enabled from that kind of source document when the link is let go. If every pair from it has been switched off, the link is marked deleted and nothing comes back — no message, no log — and where the order’s queue row had already gone to zero, it is recreated only for a pair that is still enabled. Switch a pair off after the corrections, not before.

Aging snapshots are removed — all of them. The monthly aging snapshot rows for that document are deleted permanently, with no date limit. So a voided invoice disappears from last month’s aging report and every earlier one, not just this month’s. If you print aging reports for the auditor, print them before you void, because the void rewrites the history.

What a void will not do

Seven limits. Each of these is a thing a reader has assumed and been wrong about.

  1. It will not recall an e-invoice that has already gone to LHDN. The void removes the document from the submission queue only while the submission has not happened. Once it has been submitted, the queue row and the submission record both stay, and nothing about a void reaches LHDN. The correction there is a cancellation request inside 72 hours or a credit note after — see Cancelling and correcting a validated e-invoice. For a sales invoice you will not get this far, because the refusal in the next section stops you first; for a cash bill you can, and that is exactly the case to watch.
  2. It will not give the document number back. A voided document keeps its number permanently; nothing returns a number once it has been written onto a document. See Document numbering, which has the counter and the one exception (a save that is rolled back before the number is written).
  3. It will not remove the original journal from the ledger, or the original movement from a stock movement report. Both shapes above leave the original standing on purpose.
  4. It will not reverse a foreign-currency document’s journal. The reversal path refuses a forex document outright. If you void one, the rest of the void proceeds and the journal reversal does not happen — and nothing on the screen says so.
  5. It will not reverse a journal that does not exist. A document that is FINAL with no journal behind it has nothing to reverse, and the reversal job fails rather than doing nothing visible. (The document is Final but it is not in the general ledger is the same problem seen from the other end.)
  6. It will not tell you when one of its jobs fails. The void’s ten jobs run after your screen has come back. A failed one writes a row to an error table and raises nothing you will ever see. This is the general condition described in How work actually runs, and it is why the check below exists.
  7. It will not be undone. There is no un-void, on any document type.

And one we could not establish, stated as such. Several things Finalise starts have no void counterpart in the processor registry — sales commission, budget commitments, finance charges, coupons, and webstore or marketplace status updates among them. (One is established: the intercompany counterpart in your other company is left standing by a void of either side — see the intercompany pair below.) We have confirmed the absence of a registered void subscriber for each; we have not confirmed what that means for your data in every case, because some of them are reversed elsewhere (the aging snapshot and the e-invoice queue both are, inline, without a subscriber), some are genuinely irreversible (an order confirmation e-mail, once sent, stays sent), and some may simply be left standing. If you rely on commission, budgets or intercompany postings, check them by hand after a void and tell us what you find.

When BigLedger refuses to void at all

Four refusals, all checked before anything is written, so a refused void changes nothing.

The document has been used downstream. If any other document has been raised from this one — an invoice from this order, a delivery order from this invoice — the void is refused and the message lists the blocking documents by type and number. That list is the instruction: void them first, in reverse order, working back from the last document to this one. This is the commonest refusal and the most useful one, because the error tells you exactly what to do.

A settlement is not a downstream link, and this surprises people in both directions. The refusal reads the document-link table — the knock-off between an order and the invoice raised from it — and a receipt voucher never writes a row there; it writes a contra. So an invoice that has been paid by contra can still be voided (unless e-invoicing takes Void away, below), and the void takes the settlement with it: the receipt goes back to being an unapplied credit on the customer’s account, and nobody is told. If you wanted the payment to stop you voiding the invoice, it will not.

Only a final document can be voided. A draft is discarded or deleted, never voided. If the button does nothing, check the posting status first.

A sales order that is already being picked. An order whose warehouse picking list is at pending picking is refused, because stock is being physically pulled against it. Cancel the pick first. (The error code on this branch says something about e-invoice, which is a mislabelling on our side — read the message, not the code.)

E-invoice is enabled for the company. This is the big one, and it surprises everybody who turns e-invoicing on. Once a company’s e-invoice status is ENABLED:

  • sales invoices, sales returns, credit notes, debit notes and refund notes cannot be voided at all from the Void button or the void API — the one route to a void is the e-invoice cancellation’s Void original document choice, which voids the document once LHDN accepts the cancellation (Cancelling and correcting a validated e-invoice, Step 3); after the 72-hour window the correction is a credit note;
  • a cash bill can be voided even after its e-invoice is Valid — the refusal is much narrower than it looks. The check looks for a submission-queue row for the bill and refuses only when one exists and the e-invoice record already reads Submitted. A successful submission deletes that queue row in the same transaction, so from the moment LHDN accepts the payload there is nothing left to refuse on: the void goes through, the bill is reversed, and the e-invoice stays Valid at LHDN with no sale behind it. The refusal bites only on a submission that stalled between LHDN accepting it and the row going — a few dozen rows across the whole estate at any moment. Voided cash bills carrying a Valid e-invoice do exist, on a couple of tenants, in single figures, which is why the till lesson teaches cancel first, then void. Since 25 September 2026 the check does not find the row at all — it looks the queue up by the wrong key — so the refusal never fires and a cash bill can be voided whatever its e-invoice status (a known issue, reported to engineering). The sequence to teach is unchanged;
  • a self-billed purchase document cannot be voided from the Void button or the void API — that refusal reads the document’s self-billed flag, whatever the company’s e-invoice status.

This is not a bug and it is not a permission you can be granted. It is the platform refusing to let you silently cancel a document that a tax authority has a copy of. If you enabled e-invoicing last month and “void stopped working”, this is why — and it is the “before this I could” shape that turns up across the whole corpus.

Undo to Draft and Discard, the two buttons that are not a void

Void is the one with ten subscribers. The other two are much smaller than they look, and the difference matters most to whoever reaches for them expecting a rewind.

Undo to Draft releases links. It does not unpost anything

Taking a finalised document back to Draft publishes to exactly one subscriber — the knock-off open queue — so what it undoes is the linkage: the source order gets its outstanding quantity back (on the same condition as a void) and the document stops holding it. Every posting the document made is left exactly where it was. The journal is still posted, the stock movement is still on the ledger, the cash book line is still there, the tax is still filed, the points are still awarded. Only the word at the top of the screen changes. The settlements stay too: pull a receipt voucher back to Draft and every invoice it paid still reads paid, by a receipt that is no longer final. (A processor that would set a document’s contras back to draft on undo is registered in the platform, and nothing publishes to it — the undo fan-out has the one subscriber and it is not that one.)

That has one consequence nobody expects, and it is the reason to read this paragraph twice:

Re-finalising a document that has been pulled back to Draft does not post it again. Each subsystem refuses a second posting on its own terms. The journal step refuses outright, and the refusal goes into the background error table rather than onto your screen. The stock step is quieter still: it posts only when the document’s inventory status is blank, and after an undo it is POSTED, so the step runs, writes nothing, raises nothing and reports success. The cash book behaves like the journal.

So if you take a finalised invoice back to Draft, change a quantity or a price, and finalise it again, the document says one thing and your ledger says another, with nothing anywhere to tell you. There is no message, no failed-job badge on the screen, and the posting status still reads POSTED — which is true, and is about the old figures.

Which is why the button is deliberately rare. Undo to Draft was built for documents that post nothing at all — quotations, sales orders, purchase orders, requisitions, shopping carts, marketplace orders pulled back for re-sync. For those a link release is the whole consequence, and one subscriber is exactly the right number. It is hidden by default everywhere it exists: it appears only where an administrator has switched on the show draft button setting or granted the matching permission, and only in a small minority of applets.

Six of the seven are exactly that kind of document — a quotation, an order, a requisition, a marketplace order, an outbound delivery order — and every one of them carries a quantity and amount signum of zero, so finalising posts no journal and moves no stock and the undo genuinely undoes everything there was. One is not: the purchase goods-receipt (stock-in) listing offers DRAFT as a bulk action over selected finalised rows, and that document does move stock. There, treat the button as a way to correct a document whose chain has not run, never as a way to edit one whose chain has. If it has posted, void it and key a new one.

Undo to Draft goes through only the first two of the refusal checks a void meets: the document must be final, and a document that has been used downstream is refused with the same list of blocking documents. The e-invoice refusals and the picking-list refusal apply to a void only. None of the screens that offer the button is for a sales invoice, return or note, so on screen this rarely matters. It does matter to anyone moving documents through the API: on an e-invoice-enabled company, an undo is not stopped the way a void is. Treat a document that has gone to LHDN as final, and correct it with a credit note or a cancellation, never an undo.

An intercompany pair is two documents, not one

When a sale in one of your companies raises its counterpart in another — a purchase invoice created by the intercompany pairing — the two are linked in the Intercompany menu and nothing else. Voiding either leaves the other standing, and the counterpart does not block the void the way a knocked-off document does. Each side is corrected in its own company.

And the pairing runs on every finalise. Take a paired document back to Draft and finalise it again — the sales invoice screen does not offer that, but some order screens and the API do — and the other company receives a second counterpart, because nothing looks for the first. So on a paired document, Undo to Draft is not a correction at all: correct it with a return, which pairs the right way round, and read the Purchase Credit Note and Sales Debit Note cautions before pairing a note.

Discard is for something that should never have existed

Discard publishes to two distinct processors — the AR/AP contra and the knock-off open queue — plus the serial-number, batch and bin unlock, so it releases everything the document was holding and reverses nothing, because there is nothing to reverse. The quantity a discarded draft was holding goes back to its source order on the same condition as a void — only while a knock-off pair from that kind of source document is still enabled for the company. It is refused outright on anything already FINAL or VOID, with “Generic Document cannot be discarded!”: discard is a drafts-only operation, and if the button appears to do nothing on a finalised document, that is the reason.

A discarded document keeps its number, keeps its rows and stays visible to a search. Nothing in the platform returns a document number to the pool — see Document numbering.

And one route with no fan-out at all

There is a third, non-UI endpoint that sets a document’s posting status to nothing — neither VOID, nor DRAFT, nor DISCARDED. It runs none of the refusal checks and publishes to no processor, so a finalised document can be returned to an unposted state with every one of its postings left standing and no reversal queued. It exists for data repair by an integration key and it is not reachable from any applet screen. If your integration partner has it wired into a workflow, that is worth knowing about before month-end rather than after.

And one document class where the void lands somewhere else entirely

A document raised in a currency other than your company’s does not carry its own postings. When you finalised it, BigLedger built a base-currency twin of it and ran the whole fan-out against the twin; the document you are looking at was saved without queueing anything. Void follows the same rule and sends the void fan-out to the twin as well — along with the removal of the e-invoice queue row and the removal of the historical aging snapshots.

That is right for everything the twin posted, and it has one consequence worth knowing before you press it. Your knock-offs are almost certainly on the document, not on the twin — the twin has no document number, so it is the one on the Contra tab you would never pick. The void then deletes the twin’s contras, of which there are none, and the settlement you applied to a foreign-currency invoice survives the invoice being voided, as does the realised gain or loss journal that settlement wrote.

Both documents are offered on that tab, incidentally: the contra picker asks for finalised documents for this customer with a positive balance and filters on nothing else, so the twin is listed beside the original. The aging and debtor reports are the opposite — they exclude twins by name, which is why the balance they show for a foreign-currency invoice is the foreign-currency figure, unconverted, sitting in a column of company-currency ones.

Undo to Draft does not touch the twin at all: it stays FINAL, the document goes back to DRAFT still pointing at it, and re-finalising then fails with Generic Document has already been convert to shadow. For a foreign-currency document, void and re-raise is the only route back.

Before voiding a foreign-currency invoice, delete its knock-offs from the Contra tab first, and check afterwards that the aging no longer carries it.

What success looks like: the thirty-second check

A document does not have one posting status. It has one per subsystem — journal, inventory, cashbook, tax, membership and a dozen more besides — and they move independently. That is precisely what makes a half-finished void diagnosable.

Open the voided document and go to its Posting tab, where the applet has one. You are looking at journal, inventory, cashbook, membership and tax status side by side.

Not every applet has that tab, so pick the document you test on. A sales invoice or a purchase invoice has it; the receipt voucher, payment voucher, purchase refund note and sales return do not, and POS General has never had one. Those applets carry a TraceDocument tab instead — the same five subsystems, shown as the rows that were written rather than as status words — and a cash bill has neither, so for POS the route is how to tell whether the posting happened. Run the test below on a sales invoice and you get the statuses side by side, which is what makes a half-finished void readable at a glance.

On a void that finished, every subsystem the document used reads VOID.

Read it like this:

What you seeWhat it means
All relevant statuses VOIDThe void completed. Any leftover you see in a report is one of the “original stays” shapes above — go add up the two rows.
Some VOID, some still POSTEDThe void partly ran. One of the ten jobs failed. This is real and it is what you came here to find.
A status blankThat subsystem did not post in the first place, so the void had nothing to undo there. Not a void failure — a Finalise one.
FAILEDRare. Nothing on the void path sets it; treat it as a partial run.

Then, if it is a partial run, open Trace Document in the Financial Report applet. It checks the named document for the artefacts a completed void should have left and puts a Resolve button on each one that is missing. It will not tell you why before you press it: the reason arrives as the backend’s own error message, in place of the check, when a Resolve fails — and for most partial voids that is the first time anybody sees it. And raise it — a stuck void does not re-drive itself.

Two more checks worth thirty seconds each, in the cases where they apply:

  • Voided a receipt or payment? Open the invoices it was knocking off. Their outstanding balance should be back. If it is not, the contra reversal is the job that did not run.
  • Voided something that was bank-reconciled? Open that reconciliation. The statement line should be back on the unmatched list. It being there is correct; it being absent means the cashbook removal did not run.

Common mistakes

Voiding a prior-period document without looking at the date. The reversal lands in the original period. Look at the document date first; if the period is closed or reported, a corrective document in the current period is usually what you actually wanted.

Reading a movement report as a balance. A void adds movements. Two rows netting to zero is a completed void, not a phantom one. Check the stock balance.

Voiding the invoice before the payment. The refusal will stop you, but people then void the payment, re-try, and lose track of what they have unwound. Work backwards from the newest document and write the list down first.

Assuming the void reached LHDN. It did not, and after submission the platform will not even let you try. Use the cancellation path.

Treating “still showing” as “failed” within the first minute. The void queues its work and waits for the next tick. Refresh before you investigate.

Printing the aging report after the void. The snapshots are gone by then — for every month, not just this one.

Related documentation

Last updated on