I can recall that back then, in the good old Excel VBA days, at some point, I was very busy with error handling to make it easier for the user to understand the logic of my program. One article was particularly illuminating for me: Error handling via an error class, by Dick Kusleika.
The languages M and VBA don’t have much in common, but also in M I want raise custom errors, when if something contradicts the business logic. Providing the user with a meaningful error message can greatly increase the acceptance of the program. This article deals with how you can gracefully handle custom errors in M.
Recommended ressources about standard error handling in M
Of course some M-enthusiasts in the community have already dealt with the topic of error handling and I recommend you to have a look at these as well:
- https://www.poweredsolutions.co/2019/10/28/step-level-error-in-power-bi-power-query/
- https://www.poweredsolutions.co/2019/06/18/error-handling-iferror-in-power-bi-power-query/
- https://blog.crossjoin.co.uk/2014/12/22/viewing-error-messages-for-all-rows-in-power-query/
Miguel Escobar highlights in the first of the mentioned posts, that you can raise your own (custom) error messages, if you want to.
What are custom errors and when are they useful?
Power Query/ M returns its own error messages when you try to evaluate an expression that M cannot evaluate. For example, the expression A + 1
returns the following error message.
But what if you want an error message to be returned on an expression that could be evaluated by M but doesn’t fit into your business logic?! In the following example, I want an error message to be returned whenever the tax percentage is not 7% or 19%.
The purpose of custom errors is to return error messages when the expression is technically evaluable but contradicts your own business logic. In this case, it is good and right to provide the user with the right information so that he can correct the error as quickly as possible. Let’s see how this can be done.
The manual version
You can throw a custom error by using the keyword ‚error‘ followed by the function Error.Record(). Within the function you can define up to 3 arguments, which are:
- reason as text,
- optional message as nullable text and
- optional detail as any
The following screenshot shows how to manually generate this error message in a calculated column:
But what if I want to check for this (logical) error in many places in my queries? Do I then have to write this Error.Record manually each time, or copy it from one of my previous solutions? To avoid this manual process, I have written my own function that fixes this problem!
Using a custom error function for convenience
Whenever it makes sense, I outsource tasks to custom functions that I can then reuse. This reduces the risk of errors, makes my code clearer and easier to maintain. My goal in calling my custom error therefore looks like this:
So instead of manually rewriting (or copying) the Error.Record at any necessary point in my code, I want to define it centrally at one point and then call it (based on its ID) via a function from any of my queries. I’ll show you how to do this now.
The function fnReturnCustError()
I have commented on the functionality of my function directly in the source code and hope that this is sufficient to understand it.
I hope this was interesting for one or the other. I am sure that this method can be further developed. If you succeed, please let me know.
Greetings from Germany,
Lars
Lars ist Berater, Entwickler und Trainer für Microsoft Power BI. Er ist zertifizierter Power BI-Experte und Microsoft Trainer. Für sein Engagement in der internationalen Community wurde Lars seit 2017 jährlich durch Microsoft der MVP-Award verliehen. Lies hier mehr…
milang meint
Yes, I see the point.
Than maybe create a table for error thought Enter Data form in PQ with four columns (reason, message, detail, InternalDescription) convert it to records, and filter the record Id?
It would be easier to maintain.
Lars Schreiber meint
Thanks Milan,
I am aware of those possibilities. This solution is more a thought-provoking impulse than a mature, ready-made solution. 🙂
milang meint
Maybe we do not have to convert error record to table.
Just filter the record by its id.
….
ErrorRecord = try ListCustomErrors{IDCustErr-1} otherwise error Error.Record( „Error ID not existing!“, „The error ID doesn’t exist! Use an existing one!“),
Result = error Error.Record( ErrorRecord[reason], ErrorRecord[message], ErrorRecord[detail] )
in
Result
Lars Schreiber meint
Hi Milan,
yeah, for sure. You’re right. In the development process, it was convenient to see the error messages in a table, but for the performance of the function your way is shorter, even though I don’t expect a big performance impact, because this error table won’t get thousands of rows long (I hope ;-P ). Thanks
Lars