Almanac
Microsoft/power-appsPower Platform

Consultant KB for Microsoft Power Apps: canvas apps, model-driven apps, Power Fx, data and connections, controls and UI, code and extensibility, mobile and offline, ALM and solutions, governance and security, licensing and performance, plus cross-cutting decision guides. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Power Apps release plans, docs repo and product blog, plus the author's own consultant notes.

feature-error-handling-in-power-fx.mdv1 · history
CurrentApplies to BothUpdated last monthSource Microsoft Learn

What it does

Errors in Power Fx flow through formulas the way #DIV/0! flows through Excel cells — the error replaces the value and propagates to anything that depends on it. IfError, IsError and IsBlankOrError let you catch an error inside a formula, App.OnError gives you one central place to control how unhandled errors are reported, and Error lets you create or rethrow one.

Key facts

  • This behaviour needs formula-level error management, which is on by default for new apps. Older apps may have it disabled under Settings > Updates > Retired > Disable formula-level management.
  • App.OnError can't replace an error. By the time it runs the error has already happened and already propagated. It controls reporting and logging only.
  • If App.OnError is empty, the default banner shows FirstError.Message. Defining any formula there suppresses the banner unless you rethrow with Error( FirstError ).
  • FirstError and AllErrors are scope variables available in both IfError and App.OnError. AllErrors is a table in the order the errors were encountered.
  • Errors aren't observed until a formula uses the value. If( false, 1/0, 3 ) reports nothing, and Setting a variable to an error reports nothing until something reads the variable.
  • Chained behaviour formulas don't stop at the first error. The second Patch runs even if the first failed. IfError's third argument is where you put the actions that should only run when there was no error.
  • ForAll iterations are independent and don't stop on error either. It completes and returns all the errors it hit.
  • Errors can live inside tables. One bad record doesn't invalidate the whole table, though an error thrown during Filter puts an error record in the output in place of the original.
  • The data-modifying functions — Patch, Collect, Remove, RemoveIf, Update, UpdateIf, SubmitForm — report twice: as a return value you can catch, and through the Errors function afterwards.
  • Custom error values above 1,000 are reserved for you; below that risks colliding with future system ErrorKind values.

When to use / skip

Every app that writes to a data source needs a deliberate answer to "what does the user see when the save fails". The default banner is fine for a prototype and embarrassing in production — it shows platform wording to someone who just wanted to submit a timesheet. Handle the specific errors you can predict with IfError at the point they occur, use App.OnError as the safety net and the logging hook, and rethrow anything you didn't expect rather than swallowing it. Suppressing errors globally with an empty-ish App.OnError is the pattern that produces apps which silently lose data.

Configuration decisions

  • Which errors get handled inline, which get rethrown, and which get suppressed — and who signs off on the suppression list.
  • Whether App.OnError writes to Trace for Application Insights, to a Dataverse log table, or both.
  • What the user actually sees on failure: a notification, an inline #Error, a form-level message via the Errors function, or a retry.
  • Whether behaviour formulas stop at the first error, which means deliberately structuring chained actions inside IfError.
  • Which ErrorKind values you branch on, since Network, Conflict and ConstraintViolated deserve different user messages.

Gotchas

  • Defining App.OnError at all suppresses the default banner. Add a Trace call for logging and you've silently turned off every error message in the app unless you also rethrow.
  • App.OnError formulas evaluate concurrently and can overlap. Setting a global at the top and reading it later in the same formula is unreliable — use With for anything formula-local.
  • Duplicate banners are suppressed, so a repeated error may show once. That makes "it only happened once" an unreliable report from a user.
  • Because errors aren't observed until used, a broken formula can sit in an app for months and then surface the moment someone adds a label bound to that variable.
  • IfError wrapped too broadly catches everything, including the bugs you wanted to see. Narrow it by checking FirstError.Kind and rethrowing the rest.

Consultant notes

  • Agree the error-handling pattern before the first screen is built and put it in the build standard. Retrofitting IfError across a finished app is tedious and always gets deprioritised.
  • Make sure the Application Insights connection string is set on the App object early. Without it, Trace calls go nowhere useful and you're debugging production from screenshots.
  • Check the formula-level error management switch on any app you inherit. Older apps with it disabled behave differently enough that the patterns in this doc simply won't work.
  • Warn the client that a save failing silently is worse than a save failing loudly. When someone asks to "hide those error messages", that's the conversation to have.

Worth revisiting if App.OnError ever gains the ability to replace an error, or if the ErrorKind list expands.

Was this accurate?