A few days ago I wrote a blog about Actionable Errors. We learnt that Actionable Errors are designed to help users identify, navigate to, and resolve errors more efficiently. And we saw the two approaches for Actionable Errors: fix it or show it.
We also saw a new data type, ErrorInfo.
In this blog post and the accompanying video, you will learn a few things about:
- ErrorInfo Data Type
- ErrorInfo – collectible and not collectible
- ErrorInfo Methods
- ErrorBehavior attribute
- TestField and FieldError use with ErrorInfo
But how, from talking about ErrorInfo we get to Collectible errors?
Errors of type ErrorInfo can be set as Collectible with code like:
MyErrorInfo.Collectible := true or MyErrorInfo.Collectible(true);
ErrorInfo variables created with this Collectible attribute set to true won’t be shown to users at run time when they are raised, but at the end of the procedure that contains the code that creates and initializes them.
There is though another condition for all this to actually happen. The procedure that initiates these collectible ErrorInfo needs to have the attribute ErrorBehaviour set like below:
[ErrorBehavior(ErrorBehavior::Collect)]
And this is a sample that contains both conditions to have a collectible error :
[ErrorBehavior(ErrorBehavior::Collect)]
local procedure MyCollectibleErrorProc()
begin
Error(ErrorInfo.Create('Error 1', true));
Error(ErrorInfo.Create('Error 2', true));
end;
First, notice how the create is called without a variable, that is because the Create is a static method and static method are called by the class itself. Secondly, the second parameter denotes the Collectible property. If we don’t specify true for second parameter, it wont be a collectible error.
Another way of achieving the same:
[ErrorBehavior(ErrorBehavior::Collect)]
local procedure MyCollectibleErrorProc()
var
E1, E2 : ErrorInfo;
begin
E1 := ErrorInfo.Create();
E1.Message('Error 1');
E2 := ErrorInfo.Create();
E2.Message('Error 2');
end;
When calling ErrorInfo.Create() we get automatically a collectible error without the need for Collectible property set to true.
A bit more about ErrorBehaviour. The method that creates the errors is tagged with attribute ErrorBehaviour. This attribute will dictate which methods can collect errors and which ones can’t. Right now, the only value ErrorBehaviour attribute can have is, Collect.
Where would I use this concept of Collectible errors?
- checking journal lines
- on custom interfaces where first, I stage records imported from somewhere else, via API calls or with a custom File Import process, and second I process these staged records. With custom imports you’re getting yourself in the ErrorTown so you need a solid method, like Collectible errors, of dealing with them.
I built an example of how Collectible errors and ErrorBehaviour works.
Check it out here on my github or watch me as I write the code in the video below:
Finally, let’s look at the 5 points exposed in the begining:
- ErrorInfo Data Type
- ErrorInfo – collectible and not collectible
- ErrorInfo Methods
- ErrorBehavior attribute
- TestField and FieldError use with ErrorInfo
1. ErrorInfo Data Type
There is not much to say than please check Microsoft Learn page: ErrorInfo Data Type – Business Central | Microsoft Learn
2. ErrorInfo – collectible and not collectible
Discussed above
3. ErrorInfo Methods

I used in my previous blog PageNo(), AddAction(), AddNavigationAction(), TableId() methods.
In the video accompanying this blog I used CallStack().
4. ErrorBehavior
Discussed above in this blog.
5.TestField and FieldError use with ErrorInfo
If you want to collect errors raised by TestField and FieldError you can now do that.
Here are a few examples from Base Application:
FieldError
Do you recall an error on general journal like Field 1 must have the same sign as Field2: “Amount” must have the same sign as “Amount $” ?
We can see this FieldError implemented with ErrorInfo in codeunit 11 “Gen. Jnl.-Check Line”:
if ((GenJnlLine.Amount < 0) xor (GenJnlLine."Amount (LCY)" < 0)) and (GenJnlLine.Amount <> 0) and (GenJnlLine."Amount (LCY)" <> 0) then
GenJnlLine.FieldError("Amount (LCY)", ErrorInfo.Create(StrSubstNo(Text003, GenJnlLine.FieldCaption(Amount)), true));
TestField
Same codeunit is packed with TestField + ErrorInfo samples:
if GenJnlLine."Bal. Account No." = '' then
GenJnlLine.TestField("Account No.", ErrorInfo.Create());
if GenJnlLine."Applies-to Doc. No." <> '' then
GenJnlLine.TestField("Applies-to ID", '', ErrorInfo.Create());
if (GenJnlLine."Account Type" <> GenJnlLine."Account Type"::"Bank Account") and
(GenJnlLine."Bal. Account Type" <> GenJnlLine."Bal. Account Type"::"Bank Account")
then
GenJnlLine.TestField("Bank Payment Type", GenJnlLine."Bank Payment Type"::" ", ErrorInfo.Create());
ErrorInfo provides now a way to collect the errors and display them at the end of an attempt to run a process. This new feature has been out there for a few years (2-3 years) so if you haven’t been using too much, use it, your customers will thank you!
