Salesforce Flow error handling is the difference between an automation platform you trust and one that fails silently at 2am. Most flows in production orgs have no fault paths at all — they were built on the happy path, and the first data condition outside it rolls back a user’s save with an unhandled fault error nobody can explain. This guide covers how flow failures actually behave at the transaction level, and the handling patterns that hold up in production, current to Summer ‘26.
This builds on the decision framework in Record-Triggered Flows vs Apex Triggers — once you’ve chosen flow, error handling is where that choice gets tested.
What actually happens when a flow fails
The behavior depends entirely on the flow type, and most misconceptions start here.
Record-triggered flows run inside the record’s database transaction. An unhandled element failure fails the interview and rolls back the entire transaction — including the record change that triggered the flow, every other automation in the same save, and any records created earlier in the flow. The user sees an unhandled fault message; the save simply doesn’t happen.
Screen flows have internal transaction boundaries: every Screen and Pause element commits the pending transaction. A failure rolls back only the work since the last boundary — anything committed before a screen the user already passed stays in the database. This is why a half-completed screen flow can leave real records behind: that’s by design, and your error handling has to account for it.
Scheduled and platform-event-triggered flows fail per interview. There’s no user to see an error — without explicit handling, the only signal is an email.
Fault paths — the core mechanism
Every element that can fail — Get, Create, Update, Delete Records, Action calls, Apex invocations — exposes a fault connector: draw the normal connector first, and the next connector from the same element becomes the fault path. Inside it, $Flow.FaultMessage carries the actual error text.
The minimum viable fault path does three things:
- Persists the failure — create a record in a custom
Flow_Error_Log__cobject: flow name,$Flow.FaultMessage, triggering record Id, timestamp - Alerts someone — a custom notification or a post to an alert channel
- Decides the user experience — re-throw a clean message via Custom Error (record-triggered) or route to an error screen (screen flow)
Get Records ──→ [normal path continues]
│
└─ fault ──→ Create Flow_Error_Log__c ──→ Send Custom Notification ──→ Custom Error
The anti-pattern worth calling out: a fault path that shows “Something went wrong” and ends. That catches the error and then destroys the only evidence it happened. A swallowed fault is strictly worse than an unhandled one — at least the unhandled one sends an email.
Custom Error — validation rules, upgraded
The Custom Error element (record-triggered flows) blocks the save and shows your message — in a window or attached to a specific field — exactly like a validation rule, but with the full reach of flow logic: cross-object checks, queries, formula chains, prior-value comparisons.
Two production rules for it:
- Use it for deliberate rejections (“Closed Won requires a signed contract”) — business rules, written for the user
- Use fault paths for unexpected failures — system errors, written for the admin
Mixing the two — surfacing raw $Flow.FaultMessage to end users via Custom Error — leaks internal object names and element labels to people who can’t act on them. Log the raw message; show the human one.
Roll Back Records — screen flows only
The Roll Back Records element reverts the current transaction’s uncommitted changes in a screen flow. Its real use case is multi-step wizards: if step 4 fails after steps 1–3 created records in the current transaction, a fault path into Roll Back Records leaves no partial data.
The transaction-boundary caveat applies with full force: Roll Back Records cannot undo anything committed at a previous Screen or Pause. If your wizard commits at each screen, rollback protects only the latest step — design the commit points first, then the rollback story.
Retry — the pattern Flow doesn’t ship
Flow has no native retry. For transient failures — callout timeouts via external services, record locks, momentary integration outages — the production pattern is:
- Fault path publishes a platform event (or creates the error log record) carrying everything needed to retry: record Id, payload, attempt count
- An async subscriber retries — a platform-event-triggered flow for simple cases, or a Queueable with a Finalizer for anything needing backoff and a retry ceiling (the mechanics are in the async Apex guide)
- Attempt count caps the loop — a retry pattern without a ceiling is an infinite loop with extra steps
Record-lock errors (UNABLE_TO_LOCK_ROW) deserve a special mention: they’re the most common transient failure in flow-heavy orgs, and the correct fix is usually reducing contention (fewer parallel automations on the same parent records), with retry as the mitigation, not the cure.
Governor limits apply — fully
Flows run under the same transaction limits as Apex: 100 SOQL queries, 150 DML statements, CPU time, the lot — the same ceilings detailed in the governor limits guide. The flow-specific traps:
- Get Records inside a Loop = SOQL inside a for loop. With 200 triggering records it’s an instant limit violation. Query once before the loop; filter with Collection Filter.
- Create/Update inside a Loop = DML inside a loop. Assign to a collection variable in the loop; do one Create/Update after it.
- One interview per record, shared limits per batch — record-triggered flows process a 200-record DML batch as 200 interviews sharing one transaction’s limits. Per-record inefficiency multiplies by 200.
A fault path cannot save you from a limit exception — limits kill the transaction outright, fault paths included. Limit-safe design is prevention-only.
Monitoring — the part everyone skips
Three settings turn flow failures from invisible to operational:
- Setup → Process Automation Settings → Send Process or Flow Error Email → Apex exception email recipients. The default — emailing whoever last modified the flow — is how errors disappear when people change roles.
- Setup → Paused and Failed Flow Interviews — review weekly; failed resumable interviews sitting here are silent data loss in progress.
- A report on
Flow_Error_Log__c— once fault paths log consistently, error volume per flow becomes a dashboard metric, and a spike becomes a page instead of a surprise.
The pattern across all of it: flow errors are only as visible as you design them to be. Fault paths, Custom Error, rollback and retry are the vocabulary — the discipline is refusing to ship an element that can fail without deciding, explicitly, what happens when it does.
Test your knowledge — Automation
10 questions · Basic to Advanced