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
Last updated: July 2026

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, Trace first and then rethrow with Error( 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 With to 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

FormulaReturnsUse it to...
IfError( f, fallback )f's value, or the fallback on errorSubstitute a safe value
IsError( f )BooleanBranch logic on failure
Errors( DataSource )Table of errorsInspect 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 blankCatch bad data before a Patch
Error( FirstError )Raises an errorRethrow 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.

Test Your Knowledge

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?

A
B
C
D
Test Your Knowledge

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?

A
B
C
D