9.3 Implementing Error Handling in Canvas Apps
Key Takeaways
- IfError replaces an error with a fallback value (and supports chained fallbacks evaluated left to right); IsError only reports whether an error occurred and cannot substitute a value
- Errors( DataSource ) returns a table of server-side write errors after Patch, SubmitForm, or Remove — test it with IsEmpty immediately after the operation
- App.OnError runs with FirstError and AllErrors in scope but cannot replace an error's value; it controls reporting only, and you rethrow with Error( FirstError ) to keep the default banner
- Notify shows a banner with NotificationType Error, Information, Success, or Warning and displays for 10 seconds by default
- Validate( DataSource, Column, Value ) surfaces validation problems before a write, and flow failures should be returned through the 'Respond to a PowerApp or flow' action and caught with IfError
Unhandled errors in a canvas app surface as red banners and blank controls — tolerable during development, unacceptable in production. The AB-410 exam expects you to handle errors deliberately at three levels: inside formulas, against data sources, and globally on the App object.
How Power Fx treats errors
An error is a value that flows through a formula. Division by zero, a failed connector call, a blank record where a value was expected — each produces an error value, and evaluation generally continues rather than halting. If nothing handles the error, the affected property shows blank and the app raises a red error banner. Your job as a maker is to decide which errors become fallback values, which become notifications, and which should be logged.
IfError: replace the error with a value
IfError( 1/Slider1.Value, 0 ) evaluates the first formula; if it returns an error, IfError returns the fallback instead. IfError accepts chains — IfError( Formula1, Fallback1, Formula2, Fallback2, DefaultFallback ) — evaluating each pair in order and returning the first non-error result, so you can try a primary data source, then a cache, then a constant.
Two scope records are available inside the fallback formulas: FirstError (a record with fields such as Message, Source, Observed, and Kind) and AllErrors (a table of every error found). IfError works in behavior formulas too: IfError( Patch( Orders, ... ), Notify( 'Save failed', NotificationType.Error ) ) runs the notification only when the patch errors.
IsError: test without replacing
IsError( Formula ) returns true if the formula produced an error and false otherwise. The crucial semantic difference:
- IfError replaces a value — use it when you need a result regardless of failure.
- IsError reports a fact — use it to branch logic (for example, toggling a context variable that shows a retry panel) when you do not need to substitute a value.
A classic exam trap is expecting IsError to supply a fallback value. It cannot — it only returns a Boolean.
Errors(): data source errors after writes
When SubmitForm, Patch, or Remove fails server-side — a required column is blank, a Dataverse business rule rejects the change, or two users edited the same record (an ErrorKind.Conflict) — call Errors( DataSource [, Record ] ). It returns a table of errors with columns such as Column, Message, and Error (an ErrorKind value like ErrorKind.Validation). Test it with IsEmpty immediately after the write:
If( IsEmpty( Errors( 'Order List' ) ), Notify( 'Saved', NotificationType.Success ), Notify( First( Errors( 'Order List' ) ).Message, NotificationType.Error ) );
For a conflict, the fix is to Refresh the data source and reapply the user's change against the current record.
Notify: user feedback
Notify( 'Your order was saved.', NotificationType.Success ) shows a banner. The types are Error (red), Information (blue), Success (green), and Warning (yellow). The banner displays for 10 seconds by default; pass a third argument in milliseconds to change it. Notify is the standard way to surface a handled error instead of letting the raw red banner appear.
App.OnError: the global safety net
The App.OnError property runs when any unhandled error occurs anywhere in the app, and it is evaluated with the same FirstError and AllErrors scope variables as IfError. Critical semantics:
- OnError cannot replace the error's value — by the time it runs, the error has already flowed through the calculation. It controls reporting only. To change the value, wrap the original formula in IfError.
- If OnError is empty, the default red banner shows
FirstError.Message. - To log an error but keep the default banner,
Tracefirst and then rethrow withError( FirstError ). - OnError formulas evaluate concurrently and can overlap with other errors, so a global variable written at the top of OnError may change before you read it later in the same formula. Use
Withto capture FirstError into a stable scoped value.
Preventing errors: Validate with Patch
Validate( DataSource, Column, Value ) — or the whole-record form — returns any validation errors before you write: required columns left blank, wrong types. Combine it with Patch for a belt-and-braces save: validate first, show messages with Notify, and only Patch when validation returns nothing.
Flow failures
When an app triggers a Power Automate flow with MyFlow.Run( ... ), design the flow to finish with the 'Respond to a PowerApp or flow' action, returning a status code and message body the app can inspect. Wrap the call itself in IfError to catch connector-level failures — timeouts, throttling — that never reach your response action, and Notify the user with the returned status.
Test error paths deliberately
Do not wait for production to discover your error handling. Force a divide-by-zero by binding a label to 1/Slider1.Value and sliding to 0, call the Error function with a custom kind and message to simulate a failure, and watch everything in Monitor, including Trace output from OnError. Test each path — IfError fallback, Errors() message, OnError logging — exactly as you test the happy path.
Error-handling cheat table
| Formula | Returns | Use it to... |
|---|---|---|
IfError( f, fallback ) | f's value, or the fallback on error | Substitute a safe value |
IsError( f ) | Boolean | Branch logic on failure |
Errors( DataSource ) | Table of errors | Inspect server-side write failures |
Notify( msg, type [, timeout] ) | (behavior) | Tell the user what happened |
App.OnError | (behavior) | Globally intercept and log unhandled errors |
Validate( ds, col, value ) | Error or blank | Catch bad data before a Patch |
Error( FirstError ) | Raises an error | Rethrow inside OnError or simulate failures |
Trace( msg ) | (behavior) | Write diagnostics to Monitor |
Exam traps: IfError chains evaluate left to right and stop at the first success. OnError cannot substitute values — only IfError can. Errors() reports data source errors, not math errors. And a blank result with no banner usually means an IfError somewhere upstream swallowed the error.
A label's Text property is 1/Slider1.Value. When the slider moves to 0, the label goes blank and users see a red banner. The maker wants the label to show 0 instead, with no banner. Which change achieves this?
After SubmitForm( EditForm1 ) fails because a Dataverse business rule rejected the change, which formula should the app evaluate to retrieve the server-side failure details for display?