Power Automate error handling in Dynamics 365 is the thing almost nobody builds until a flow has already cost them money. The flow looks fine on the day you deploy it. Three months later a connection expires, an approval never gets sent, and nobody notices for a fortnight.
I have been called in to clean this up more than once. The pattern is always the same: dozens of flows, no error handling, and a vague hope that someone would spot a problem. Hope is not a monitoring strategy.
Why Dynamics 365 flows fail silently
By default, a failed flow run just sits in the run history with a red cross next to it. Nobody is told. The person who built the flow may have left the company, and the failure notification, if one exists, goes to their old mailbox.
The other trap is that a flow can fail in the middle. The first three steps succeed, the fourth throws an error, and now your data is half updated. That is worse than a clean failure, because things look mostly right.
The usual causes
Expired connections are number one. A flow running under a personal account stops working the day that person changes their password policy or leaves.
Number two is hitting limits. Dataverse has request limits per user, and a busy flow can get throttled. I covered the detail in my post on Dynamics 365 service protection limits, and it is worth a read if your flows touch lots of records.
Number three is plain bad data. A lookup that is empty, a date in the wrong format, a record someone deleted. Real users find edge cases you never imagined.
Use scopes to build try and catch
Power Automate does not have a try and catch block with that name, but you can build exactly the same thing with scopes. This is the single most useful technique in this whole post.
Put your main actions inside a scope and call it "Try". Add a second scope called "Catch" straight after it. Then set the Catch scope to run only when the Try scope has failed or timed out, using the "Configure run after" setting.
What goes in the Catch scope
Keep it simple. Capture what went wrong, tell a human, and log it somewhere you can query later.
You can pull the error details out of the Try scope with the result function, filtered to the failed actions. That gives you the action name and the error message, which is far more useful than a generic "something went wrong" email.
Handle retries properly
Every action has a retry policy. The default is four retries with exponential back off, which is fine for temporary glitches but wasteful for errors that will never fix themselves.
If you are calling an external API that is rate limited, set a sensible fixed interval. If you are updating a record that is locked, a couple of retries is plenty. And if the error is a bad request, turn retries off entirely. Retrying bad data four times just makes four failures.
Do not retry things that are not safe to repeat
This catches people out. If your flow creates an invoice or sends an email and then fails afterwards, a retry of the whole flow can create a duplicate. Think about what happens if the flow runs twice for the same record.
The fix is to check before you create. Look for an existing record first, or store a unique key. It is the same idea I described in my guide to idempotency keys, applied to low code.
Alerts that people actually read
An alert that goes to everyone gets ignored. An alert that goes to nobody is useless. You need one named owner for each flow, and the alert needs to land where they already look.
For most of my clients that means a Teams channel for the support team, with a card that shows the flow name, the record involved, the error and a link straight to the failed run. Email works too, but it gets buried.
Log failures to a Dataverse table
I like to write every caught error to a simple custom table. Flow name, record, error text, timestamp. It takes ten minutes to add and gives you something you can chart in a view or a Power BI report.
After a month you will see which flows fail most often. It is usually two or three offenders causing nearly all the noise, and fixing those is quick.
Stop running flows under personal accounts
If I could change one habit across every Dynamics 365 project, it would be this. Do not build production flows under a named person. Use a service account, or better, a service principal connection for flows inside solutions.
When flows live inside a solution and use connection references, you can move them between environments without rewiring everything. If you are not yet working that way, my post on Dynamics 365 ALM and solution management explains how to get set up.
Know when a flow is the wrong tool
Sometimes the real answer to a flaky flow is to stop using a flow. If something has to run in the same transaction as the save, or it must never fail silently, a plugin is usually the better choice. I wrote about that trade off in plugins vs Power Automate.
Flows are brilliant for notifications, approvals and gluing systems together. They are less brilliant for critical business logic that needs to be rock solid. Be honest about which one you are building.
A simple checklist before you go live
Before any flow goes into production, I check five things. It runs under a service account, the main logic sits inside a Try scope, there is a Catch scope that alerts a named owner, the failure is logged to a table, and I have tested what happens when it runs twice.
That list takes an hour per flow at most. Compare that to explaining to a customer why their order sat in limbo for two weeks. If you would like help auditing the flows you already have, that is exactly the sort of job I take on through my Dynamics 365 services.


