Avoiding Duplicate Document Numbers in Job Queues: Use ClearStateAndGetNextNo
When working with number series in Dynamics 365 Business Central, you’ve probably used NoSeriesMgt.GetNextNo
more times than you’ve had coffee breaks. But if you’ve ever used it inside a job queue, you might have noticed something funky — like getting the same document number reused. And no, it’s not déjà vu — it’s state retention biting back.
🧨 The Problem: “Why am I getting the same Document No. again?!”
In job queues, NoSeriesMgt.GetNextNo
keeps an internal memory of the last fetched document number beacuse of it’s global variable not being cleared. This is normally fine for page-bound transactions, but it’s a trap when you run the NoSeriesMgt
instance in a job queue run.
codeunit 50000 "My Codeunit"
{
var
GenJnlLine: Record "Gen. Journal Line";
NoSeriesMgt: Codeunit NoSeriesManagement;
procedure ProcessMytable(Mytable: Record "Mytable")
begin
CreateJournal(Mytable);
PostJournal(GenJnlLine);
end;
procedure CreateJournal(Mytable)
begin
<!-- Other Code -->
GenJnlLine.Validate("Document No.", NoSeriesMgt.GetNextNo(Mytable."No. Series"));
<!-- Other Code -->
end;
procedure PostJournal(GenJnlLine)
begin
<!-- Post the journal -->
end;
}
What’s going wrong?
- The last number fetched is remembered internally.
- If you’re looping, retrying, or processing in a long-running session, that number might get reused.
- Result? ❌ Duplicate document numbers, failed journal lines, angry accountants, and awkward post-mortem calls.
Possible Solutions
Simple Solution
codeunit 50000 "My Codeunit"
{
var
GenJnlLine: Record "Gen. Journal Line";
NoSeriesMgt: Codeunit NoSeriesManagement;
procedure ProcessMytable(Mytable: Record "Mytable")
begin
CreateJournal(Mytable);
PostJournal(GenJnlLine);
end;
procedure CreateJournal(Mytable)
begin
<!-- Other Code -->
Clear(NoSeriesMgt);
GenJnlLine.Validate("Document No.", NoSeriesMgt.GetNextNo(Mytable."No. Series"));
<!-- Other Code -->
end;
procedure PostJournal(GenJnlLine)
begin
<!-- Post the journal -->
end;
}
🧯 The Solution: Use ClearStateAndGetNextNo
To break out of this Groundhog Day loop, use the following method for BC version less than 24: ClearStateAndGetNextNo
.
GenJnlLine.Validate("Document No.", NoSeriesMgt.ClearStateAndGetNextNo(GenJnlBatch."No. Series"));
✅ Why it works:
- 🧽 Clears the internal state (no lingering “last number”)
- 🔄 Ensures a new number is fetched from the series every time
- 🚀 Perfect for job queues, background services, and loops
- 🧘♂️ Eliminates side effects caused by retained memory
🔬 Side-by-Side Comparison
Method | Retains State | Safe for Job Queues? | Behavior |
---|---|---|---|
GetNextNo | ✅ Yes | ❌ No | Reuses last fetched number unless reset manually |
ClearStateAndGetNextNo | ❌ No | ✅ Yes | Always fetches a fresh number, clearing any cached state |
🧠 Best Practices
- 🔁 Always use
ClearStateAndGetNextNo
in:- Job queues
- Loops processing multiple documents
- Web service integrations
- Background tasks
- 🧑💻 Use
GetNextNo
only when working with UI-triggered or single-use synchronous processes.
🔍 Real-World Use Case
GenJnlLine.Validate("Document No.",
NoSeriesMgt.ClearStateAndGetNextNo(GenJnlBatch."No. Series")
);
In this example, we ensure every journal line created from a job queue run gets a unique document number, no matter how many entries we’re looping through.
🧷 Conclusion
Using ClearStateAndGetNextNo
isn’t just a “better” choice for job queues — it’s the only sane one. If you’re still using GetNextNo
in your async code, you’re practically inviting a duplicate-doc-no party.
🎯 Be smart. Be stateless. Use ClearStateAndGetNextNo
.