40–60% of Salesforce Flows lack fault paths. That's not a guess — it's what org audits consistently surface. A Flow without a fault path is a Flow that fails silently. The record either gets stuck in a broken state, the process exits without doing anything, or an unhandled exception bubbles up as a vague "Error occurred" screen that tells the user nothing useful.
Error handling in Flow is built around the fault connector — the dotted line that appears when you connect an element and it has a failure outcome. Adding fault paths is the single highest-impact improvement you can make to Flow reliability. This guide covers the patterns that actually work in production.
The Fault Connector: Your First Line of Defense
Every action element in Flow — Create Records, Update Records, Get Records, Send Email, Apex Actions — has a fault output. When the action fails (DML error, permission error, validation rule, governor limit), the fault path fires. If you don't connect it, the error goes unhandled and the Flow either stops silently or throws an opaque error to the user.
To add a fault path: select the connector line from any action element, drag from the center node, and look for the "Fault" outcome (shown as a dotted line with a lightning bolt icon). Connect it to a fault handling element.
Pattern 1: Fault Path → Decision → Route to Subflow
For Flows with multiple action elements, the cleanest pattern is: every action with a fault path routes to a shared Error Subflow. The subflow logs the error, decides on a response, and routes accordingly.
Error Subflow structure:
- Input variables:
FlowName,ErrorMessage,RecordId,ErrorCode,FailedAction - Decision: Is this a retryable error (e.g., UNABLE_TO_LOCK_ROW) or terminal (e.g., FIELD_CUSTOM_VALIDATION_EXCEPTION)?
- If retryable: Wait N minutes, re-attempt (with a counter guard)
- If terminal: Log to custom Error_Log__c object, notify admin via email alert, display user-friendly message
Error Subflow Design
Keep the error subflow generic so every Flow that needs fault handling calls it with different context. Never build one-off error handling inside each Flow — it duplicates logic and makes error patterns invisible to admins.
The subflow should write to an Error_Log__c custom object with fields: Flow_Name__c, Error_Message__c, Error_Code__c, Record_Id__c, User_Id__c, Timestamp__c, Retry_Count__c. This gives you a searchable audit trail of every Flow failure.
Pattern 2: Screen Flow Rollback with Transaction Security
Screen Flows present the hardest error handling challenge: the user has interacted with screens, entered data, and expects the Flow to work. When the Flow hits an error on a later screen (e.g., an Apex action fails), you need to let the user correct and retry without losing what they entered.
The problem: Flow doesn't have native transaction rollback. If you've updated records in steps 1 and 2, and step 3 fails, those updates are already committed. You can't "undo" them in Flow.
The pattern:
- Never commit DML (Create/Update) in early screens. Stage all changes in Flow variables.
- On the final screen, show a review step with a "Confirm" button.
- On "Confirm," a single DML operation (Create or Update) does all the writes at once. If it fails, the user sees the error on the same screen and can fix it — no partial state was committed.
- Add a "Save Draft" path that writes the staged data to a
Draft__ccustom object so users can close and resume later.
Process__c custom object as a state machine — write each step completion to the record as you go. On any failure, the Process record contains the full state so you can reconstruct it or clean it up.Pattern 3: Scheduled Flow Error Recovery
Scheduled Flows that run on large record sets are the most dangerous for silent failures. A scheduled Flow that hits a governor limit on record 8,000 of 10,000 silently exits — the first 8,000 records were processed, the remaining 2,000 were never touched, and there's no failure alert.
Recovery pattern:
- Add a
Processed__ccheckbox field to the object. The Flow sets it totrueon each record as it completes. - On the next scheduled run, query only records where
Processed__c = false— this picks up anything from the previous failed run. - Add a counter: a
Retry_Count__cnumber field. If the Flow fails on a record, increment the counter. After 3 failures, escalate to an admin notification instead of retrying indefinitely.
Resource: {!$Flow.CurrentDate} - {!Record.CreatedDate} > 7
AND {!Record.Processed__c} = false
AND {!Record.Retry_Count__c} < 3
Pattern 4: Get Records with "Fault if No Records Found"
Get Records elements have two fault outcomes: Fault (the query itself failed, e.g., invalid filter) and No Elements (the query was valid but returned nothing). "No Elements" is not a fault — it's a valid outcome. You must add a Decision element after Get Records to check whether the result collection has any records before proceeding.
If you skip the Decision and use the Get Records result in a Loop or an Update Records element directly, and the collection is empty, the Flow either skips the loop silently or the Update tries to update "nothing" and throws a vague DML error.
The required pattern after every Get Records:
Condition: {!Get_Records_Found.Size} > 0
If true → Continue with processing
If false → Route to "No records found" handling path
Pattern 5: Validation Rule Bypass and the Right Way to Handle It
When a Flow tries to update a record and the update fails because of a Validation Rule, Salesforce throws a FIELD_CUSTOM_VALIDATION_EXCEPTION. The Flow catches it via the fault path. The standard response is to display the validation rule error message to the user.
How to surface validation rule messages to users:
- After the fault path triggers, use a Decision to check if the error message starts with
FIELD_CUSTOM_VALIDATION_EXCEPTION. - Parse the validation message (it's appended after the exception code in the fault error text).
- Display the parsed message in a Screen element — "The update couldn't be saved: [parsed message]."
- Give the user a "Try Again" path that returns them to the relevant screen with their data preserved.
Better approach: Before making an update that might fail validation, do a pre-check. Get the record, evaluate the validation rule condition in a Decision element, and if it would fail, show the user the validation message before they try to submit. This is faster than catching the exception and gives a cleaner UX.
Pattern 6: Custom Logging — Beyond the Error Log Object
The Error_Log__c object approach in Pattern 1 gives you a searchable list of Flow failures. But for high-volume Flows, writing to a custom object on every failure creates additional DML overhead and may contribute to governor limit pressure on the Flow itself.
For high-volume Flows: Write to the Salesforce Platform Event stream instead. Platform Events are async and decoupled — the Flow publishes an event (fast, non-DML) and a separate subscriber (another Flow, an Apex trigger, or an External Service) handles the logging. This keeps the primary Flow clean of logging overhead.
For low-volume Flows, the custom object approach is fine and simpler to implement.
Testing Fault Paths Before They Go to Production
Every Flow that has a fault path needs to be tested with failure scenarios. Standard test cases:
| Test Scenario | How to Trigger | Expected Outcome |
|---|---|---|
| Permission error | Run Flow as a user without field-level access | Fires fault path, logs error, displays friendly message |
| Validation rule failure | Create a test record that triggers the validation rule | Fires fault path, surfaces validation message to user |
| Governor limit exceeded | Run on a large test data set to exceed DML rows limit | Fires fault path, partial progress stops cleanly, alert sent |
| Integration callout timeout | Mock an unreachable endpoint (e.g., in an Apex test) | Fires fault path, retry logic kicks in or escalation fires |
| Duplicate record on insert | Run with Duplicate Rules active and matching data | Fires fault path (if block rule) or alert (if allow rule) |
Use Flow Debug mode to manually trigger fault outcomes. In Debug, you can set any action element to "Force Fault" to test the fault path without needing to create the specific error condition. Run your test cases in Debug before deploying to production.
Find the Flows in Your Org That Are Missing Fault Paths
The Flow Health Auditor scans every Flow in your org and surfaces the ones with missing fault connectors, inactive elements, recursion risks, and broken paths — in minutes.
Run the Free Flow Health Scan →Auditing Your Org's Fault Path Coverage
You can't fix what you can't see. To get a full picture of your org's Flow error handling coverage:
- Export your Flow metadata via Salesforce CLI:
sf project retrieve start -m Flow:* - Parse each Flow's XML to identify elements with and without fault connectors
- Flag any action element where the fault line is not connected to another element
- Score the org by Flow: percentage of action elements with fault coverage
The Luxera Cloud Flow Health Auditor does this automatically — it reads your org's Flow metadata, scores each Flow for error handling coverage, flags specific elements missing fault paths, and surfaces the highest-risk Flows first. It also checks for inactive versions, recursion risk, and Flow versions that reference fields or objects that no longer exist.
Frequently Asked Questions
Why do my Flows fail silently — no error to the user, no record of the failure?
Because there's no fault path connected. When an action element fails and the fault connector is unhandled, Salesforce logs the failure in the Flow Execution History (Setup → Flows → select the Flow → View Execution History), but doesn't surface it to the user. Connect every action element's fault path to a fault handling subflow and you immediately gain visibility into failures.
Can I catch errors from a Subflow the same way as a direct action element?
Subflows called from a parent Flow inherit the fault handling of the parent if the subflow doesn't have its own internal fault handling. If the subflow throws an unhandled fault, it surfaces to the parent's fault path. Design subflows to have their own internal fault handling and return a status (Success / Failed / Retry) to the parent rather than letting faults propagate up.
Does Flow Builder have a try-catch equivalent?
Not in the same sense as Apex. Flow has fault paths (catch equivalents) but no "try" block isolation — if a Flow has done DML work before hitting a fault, those DML operations are already committed. The transaction rollback pattern (Stage in variables, DML in one step at the end) is the closest equivalent to try-catch in Flow.
What's the difference between Fault and No Elements on Get Records?
Fault means the query itself failed (invalid field name, invalid operator, SOQL syntax error, permission issue). No Elements means the query was valid but returned zero results. Fault should always route to an error handler. No Elements should route to a business-logic decision — sometimes "no records" means "skip this step," sometimes it means "send an alert," sometimes it means "create a new record."
My Flow runs as the System user. Do permission errors still trigger fault paths?
When a Flow runs in System Context (Without Sharing), field-level security and object permissions are bypassed. Permission errors will not fire on Get Records, but they will still fire on Create/Update if you have validation rules or data constraints that aren't permission-based. Run in System Context only when necessary and add fault paths for non-permission DML errors.
The 15-Minute Fault Path Audit
If you're looking at an org with dozens or hundreds of Flows and no idea where to start, run this quick audit:
- Go to Setup → Flows
- Filter by "Flow Type = Record-Triggered Flow" and "Status = Active"
- Open each Flow, check whether every action element has a connected fault path
- Flag any Flow without a fault path on any action element as High Priority
- Open the Flow Health Auditor to do this at org scale in minutes
The Flows missing fault paths are your biggest risk. They fail silently and you only discover it when a user reports a problem or a report shows missing data. Fix the fault paths first — it's the single change with the highest reliability ROI per hour of work.