Collecting errors and the Error Messages page

In the Business Central user interface, warnings and errors come in two different flavors: as a dialog (aka a window with text), or as the Error Messages list page.

Dialogs

We all know: To display single errors or warnings, Programmers usually call either the Error method or the Message method, respectively. Only since BC 19, we can also collect multiple errors in one error dialog. Tomáš Kapitán summarizes it in his blog post ErrorInfo data type & Collectible Errors.

Collectible errors are fine for only a short list of errors to display, but they are not suitable for a longer list, they cannot collect warnings, and they do not offer any user action to fix the errors.

Error Messages page

In order to display a long lists of errors and warnings (!), and to offer users a much more convenient way to fix them, the Error Message page has been created. It is called from every journal page by running the Preview Posting action, provided there are errors to be logged. To be honest, I don’t know when this page was introduced (it exists at least since BC 15), but over the years, the page has undergone quite some UI changes. Since BC 22, and thanks to the standard Error Messages with Recommendations extension, it looks like this:

The Error Messages page with recommended action and Details FactBox

Without the extension, the very same page is missing the Details Factox, and Recommended action colum, along with actions Accept recommended action and Hide fixed errors. However, in the Source column, there is still a link available, providing the user a one-click jump directly into the dimension list to fix:

The Error Message page without the Error Messages with Recommendations extension

As we can see, even long before the recommended actions were introduced, the page was a powerful helper for user.

The Error Message Management codeunit

The Error Message page is based on temporary Error Message records, that have been created by using Log* procedures from the Error Message Management codeunit. Running TempErrorMessage.ShowErrorMessages(true); will then open the Error Message page with all the gathered errors and warnings (if any), and the true parameter ensures that in case of existing errors, the transaction will be rolled back. If you’d like to see some code sample for this, check the How to write ERROR and CONFIRM? blog post by Krzysztof Bialowas, section “ERROR handling in the posting codeunits”.

Can we use ErrorInfo to populate the Error Messages page?

This question was the actual reason why I wrote this blog post. I have a complex app that stores numerous fields for an entity that is slightly similar to an Item, only that it has a Status field. When the user tries to release the entity, a release codeunit is run that collects errors and warnings and displays them on the Error Message page. Only if no error was logged, the Status will be set to Released.

Parts of these checks are also carried out much earlier, while the user populates fields on the entity card page. In those cases, a normal validation error message should appear, and not the Error Messages page. In order to keep my entity table clean, the validation code calls my custom codeunit, that – depending on global variable LogErrorMode – either calls the standard Log* procedures, or raises the actual error. Let’s take a look at a simplified example of my custom LogTestField procedure:

procedure LogTestField(SourceVariant: Variant; FieldNo: Integer): Boolean
var
    RecRef: RecordRef;
    FldRef: FieldRef;
begin
    if LogErrorMode then
       // Collect for Error Messages page
        exit(ErrorMessageMgt.LogTestField(SourceVariant, FieldNo));
        
    RecRef.GetTable(SourceVariant);
    FldRef := RecRef.Field(FieldNo);
    // Instant error to the user
    FldRef.TestField();
end;

After I finished my previous blog post, Moving to actionable errors, I asked myself whether the usage of ErrorInfos can now replace my custom codeunit. James Pearson wrote a very useful series of blog posts about trying actually the same, and he succeeded:

In part 3 you can see nicely, how he replaced ErrorMessageMgt.LogError(...) with Error(ErrorInfo.Create(...)). You can take a quick glance at his code changes here.

Perfect, so I dived right in. At first sight, everything that James described worked also for me: I had a filled Error Message page, setting the entity Status to Released was still being prevented in case of errors – but there were some details that made me roll back all my previous changes.

My entity consists of (many …) fields that depend on each other. For example, a validation code similar to the following one is being run, that will test field 2 only if field 1 is filled:

if not MyCustomCodeunit.LogTestField(MyRec, MyRec.FieldNo("Field 1")) then
    MyCustomCodeunit.LogTestField(MyRec, MyRec.FieldNo("Field 2"));

The release check code looks very similar. Just as in the standard Error Message Management, my LogTestField procedure has a return value to tell whether an error has been logged, hence if the field to test was empty. And this is exactly why I cannot use MyRec.TestField("Field 1", ErrorInfo) instead – there is no such return value. Of course, I could clutter my code with lots of additional ifs. For me and my huge and complex solution, this is a no-go.

Additionally, collectible errors are just errors, they cannot collect warnings, but it’s also warnings that I display on my Error Messages page. Last but not least, I found no way to pass Additional Information for the Error Messages page along with the ErrorInfo parameter. I simply could not fill the Error Messages page with all the information as before the conversion.

So long story short … I had just learned that I still had not fully grasped yet what collectible errors actually are. So maybe I’ve spared you the same experience – or have I confused you even more (oops)?

Leave a comment

Create a free website or blog at WordPress.com.

Up ↑

Design a site like this with WordPress.com
Get started