A story about one broken night · then the ten UX jobs inside it

When the recipe fails, you become a detective

You don’t need to know Flow Builder to follow this. Salesforce can run a business process for you automatically — a recipe of steps. When that recipe breaks in real customer data, the product does not tap you on the shoulder with “here’s what broke.” You reconstruct it.

What a Flow is

The kitchen metaphor

A Flow is a recipe Salesforce runs without a human clicking through screens: when this happens, look something up, decide, create a record, send an email. Flow Builder is the kitchen where that recipe is drawn as boxes on a canvas. Troubleshooting is what you do when the recipe runs against live deals and something that should have happened… doesn’t.

A renewal never appears. A lead isn’t routed. An email doesn’t send. Sales thinks Salesforce is “down.” It isn’t. One of the recipes misfired.

The sales person
Jordan

An account executive. Closes a deal as Closed Won and expects a renewal Opportunity to appear automatically. It doesn’t. Jordan files a ticket.

The admin who gets the email
Priya

Last person who edited the recipe. At 9am she has 18 nearly identical error emails — not because she owns the process, but because the product mails whoever last touched it.

The recipe
Create Renewal Opportunity

When a deal is Closed Won, look up the standard Price Book (the catalog of prices), create a renewal, email the owner. Tuesday, someone deactivated that catalog.

Tuesday night

The incident this whole page follows

Someone turns off the standard Price Book. Overnight, 18 won deals try to create a renewal. All 18 fail. Nothing in Salesforce looks “on fire.” The picture of the recipe is unchanged. Jordan can’t save his Closed Won the way he expects. Priya finds out from her inbox.

That is the whole current-state experience in one line: today’s troubleshooting is detective work across email, Setup lists, a picture that doesn’t show runtime, and a re-run that isn’t the original crime.

1 Detect
An email arrives
Inbox event, not “18 renewals are broken”
2 Locate
Hunt the box
Named in text, found by eye
3 Diagnose
Try it again yourself
You cannot rewind 2:14 AM
4 Fix
Save a new version
Verify against a case you invented
5 Prevent
Deploy and hope
No picture of what changed

Words you’ll see below

Price Book
The catalog of prices a deal uses. Turn it off, and anything that looks it up comes back empty.
Canvas
The drawing of the recipe. It does not light up when the recipe fails in production.
Debug
Run the recipe again now, with a record you pick — not a replay of the failure that already happened.
Subflow
A recipe that calls another recipe. The failure is often inside the inner one, which you cannot open from the outer debug.
Apex
Real code. When a Flow calls it, you debug in two products.
Governor limits
Salesforce’s usage caps. One record is fine; 2,400 overnight can blow the budget halfway through.
3rd
Cited Flow challenge in the ALM survey — behind performance and testing
117
Mentions of debugging / troubleshooting (n=472, top-2 pick)
16
Enterprise interviews, Mar 2025 (Sneha Murali)
10
Scenes in Priya’s morning, below
1

The news arrives as 18 emails

Priya didn’t get a dashboard that said “18 renewals are broken.” She got eighteen copies of a technical dump, because she was the last person who edited the recipe — even if she changed teams. Jordan still doesn’t know why his deal didn’t create a renewal.

Something broke overnight. You find out from a plain-text interview dump in the inbox of whoever last modified the flow — not from a health view.

Detect Fault email Paused & Failed Interviews Flow Logs GA Spring ’26
Inbox — 18 unread from FlowApplication
×18
FromFlowApplication@salesforce.com Topriya.nair@acme.com · last modified this flow TimeToday 2:14 AM · and 17 more like it
Error Occurred During Flow “Create_Renewal_Opportunity”: Get_Standard_Price_Book
An error occurred at element Create_Renewal_Opportunity. The flow tried to create a record. You can look up ExceptionCode values in the SOAP API Developer Guide. Error ID: 889849941-86152 Error element: Create_Renewal_Opportunity Error message: The flow failed to access the value for Get_Standard_Price_Book.Id because it hasn't been set or assigned. FLOW_INTERVIEW_VALUE Opportunity.Id = 006Dn00000kR2aX Opportunity.StageName = Closed Won Get_Standard_Price_Book = (null) priceBookId = null This email was sent to the user who last modified the flow.

What Priya does

She opens the email, then a Setup list of failed runs, then the recipe. Flow Logs would help — if the org turned them on for this flow, and is willing to spend Data Cloud credits.

Why it’s hard

No severity, no impact count, no aggregation. Eighteen failures arrive as eighteen emails, not one incident. When she hits Debug, Salesforce runs the recipe again now — it cannot rewind the 2:14 AM failure.

In human terms: “I found out from my inbox, then reconstructed it.”
2

Several recipes ran. Which one is guilty?

Closing a deal doesn’t run one recipe. It can run three Flows plus a piece of code, in an order Priya cannot see. The error is generic — the same wording shows up in several places — so it doesn’t uniquely name the culprit.

Opportunity has several flows and a trigger on the same save. The error is generic. Nothing tells you which automation threw, or in what order.

Diagnose Multi-flow on one object No execution-order view
Setup · Object Manager · Opportunity · Automation
Opportunity on create / update
Before-save
Stamp Close Date Defaults
Record-triggered flow · v6
ran?
After-save
Create Renewal Opportunity
Record-triggered flow · v4
this one?
After-save
Notify Account Team
Record-triggered flow · v2
ran?
Apex
OpportunityTriggerHandler
after update · 214 tests
ran?
? “which one fired first and why”

What Priya does

Turns on a debug log after the fact and reads it like a black-box recorder — hoping it was recording when Jordan clicked Save.

Why it’s hard

The order of multiple recipes on one object is neither visible nor controllable in the builder. The email names a box inside one recipe, not the whole transaction.

Quote from research: “You can’t really tell well which one fired first and why did it fire first.”
3

The failure is inside a recipe she cannot open

Think of a cookbook that says “now follow the sauce recipe on page 40.” The outer recipe looks fine. The failure is in the sauce. Salesforce tells her “the call to the other recipe failed” and will not let her step inside that nested run.

The parent flow looks fine. The failure is inside a subflow you cannot step into. The failure list only shows the call element.

Diagnose Subflow Black box at the call
Flow Builder · Create Renewal Opportunity v4 · Debug
Create Renewal Opportunity · v4 · Debug mode
S
Opportunity Closed Won
Start
G
Get Standard Price Book
Get Records · 0 records
F
Create_Renewal (subflow)
Subflow · failed here
Failure list: “Call Create_Renewal” — that’s all
A
Email Account Owner
Action · not reached
Debug details
Start
How the interview started · Opportunity 006Dn00000kR2aX
Get Records
Get_Standard_Price_Book · 0 records. Variable not set.
Subflow — failed
Create_Renewal. You cannot open the nested interview from here. Inputs shown; inner path is not.
Not in this panel
The element inside the subflow that actually threw.

What Priya does

Opens the inner recipe in a second tab. Guesses what inputs it received. Re-runs it alone with a record ID she typed in by hand.

Why it’s hard

There is no view of the whole transaction. You cannot navigate into the nested recipe during debug to see the step that actually threw. Linked recipes and AppExchange actions have the same shape.

4

The picture still looks healthy

After 18 overnight failures, Priya opens the recipe. It looks exactly like the day she built it. Debug means “try the recipe again with a record I pick,” not “play back what happened to Jordan at 2:14 AM.”

You want to watch variables as the flow executes. Until recently the debugger ran until it faulted or finished. The canvas still looks the same whether the flow failed 18 times or never ran.

Diagnose Step-through shipped Summer ’26 Canvas still has no run state
Flow Builder · same canvas after 18 production failures
Create Renewal Opportunity · looks healthy
Undo · Redo · LayoutDebug
S
Opportunity Closed Won
Start
G
Get Standard Price Book
Get Records
C
Create Renewal Opportunity
Create Records
E
End

What Priya does

Types in a record ID. Hits Debug. Reads a console dump. Summer ’26 added the ability to step box-by-box — a real improvement. She is still watching a re-enactment, not the original night.

Why it’s hard

The production run is gone. Live data, permissions, and other recipes don’t reproduce cleanly. Detailed logs only exist if someone turned recording on before it broke.

Quote from research: “I wish it would step through each element instead of running the entire flow until it completes.”
5

Half the story is in another product

Part of the recipe is not boxes — it’s real code (Apex). Flow Builder shows her “price book ID = empty.” The useful sentence — line 44, no rows returned — lives in a developer log in another window, and only if logging was already on.

The flow calls an Apex action. The Flow debugger shows inputs and outputs. The real stack is in Developer Console, in another window, if a trace flag was on.

Diagnose Apex action Context switch
Flow Builder debug — what you get
Debug details
Apex action
PriceBookResolver.locate
Inputs
opportunityId = 006Dn00000kR2aX
useStandard = true
Outputs
priceBookId = null
That’s the entire Apex story in Flow
No line number. No inner exception. Open Developer Console.
Developer Console — where you actually go
09:14:22.0 (0) | USER_DEBUG | [PriceBookResolver.cls:44] 09:14:22.1 | SOQL_EXECUTE_BEGIN | [SELECT Id FROM Pricebook2 WHERE IsStandard = true] 09:14:22.2 | SOQL_EXECUTE_END | Rows:0 09:14:22.3 | FATAL_ERROR | System.QueryException: List has no rows for assignment to SObject Class.PriceBookResolver.locate: line 44, column 1 Class.OpportunityTriggerHandler.afterUpdate: line 118 AnonymousBlock: line 1 09:14:22.4 | FLOW_ELEMENT_ERROR | Create_Renewal_Opportunity

Why it’s hard

She is debugging in two kitchens. That context-switch is why developers in the study still prefer to write the whole thing in code. Combined Flow + Apex is the case they cite when they say Flow is harder to trust.

6

It worked for one deal. Overnight it exploded.

Priya debugs with one Opportunity. It works. A nightly job of 2,400 deals hits Salesforce’s usage cap (too many database writes) and dies at record 528. One click of Debug never shows her that. This is actually the most-cited Flow pain in the survey — bigger than debugging itself.

A single debug run with one record looks fine. At volume — especially a scheduled flow — DML, SOQL, or CPU blows up. Users asked for Apex-test-style performance stats in the builder.

Detect #1 adjacent ALM pain (166) Flow Logs: per-element runtime
Scheduled flow · nightly renewals · 2,400 Opportunities
SOQL queries
38%
CPU time
71%
DML statements
151 / 150
Records processed
528 / 2400

Job aborted at Create Renewal Opportunity · DML exception · remaining 1,872 records not processed

What Priya does

Shrinks the batch. Splits the recipe. Watches scheduled jobs more closely because they fail more. A newer “Flow Logs” view can show where time went — if the org paid to turn it on.

Why it’s hard

A single Debug click does not exercise volume. Several recipes on the same object can pile onto the same budget. There is still no builder-native “where is the time going” view like code tests have.

7

A guided form failed. The traces are a mess.

Not every recipe runs in the background. Some are screens a person clicks through — pick accounts, next, next. When that form misbehaves, the “what happened” log is a flattened dump of fields, not a clear story of which widget broke.

A screen, repeater, LWC, or screen action misbehaves. Legacy debug traces are HTML strings. Some screen components still have no debug logs in the UI. On-canvas screen debugging is in flight.

Diagnose Screen / repeater / LWC On-canvas debugger in flight
Debug a screen · legacy
Select accounts
datatable · 24 rows · selectedRows = []
Previous Next
Open question from the spike: opening a failed screen flow from the error email — new debug run, or the failed interview?

Why it’s hard

The running form and the nested action behind a button are two different runs. Until a newer on-canvas debugger lands, Priya debugs the screen in one place and the button’s recipe in another. Even then: if she opens the failure from the email, should she see the original run — or start a new one?

8

It used to work. What did someone change?

Last week the recipe had a fallback: if the standard catalog is missing, use another. Tuesday, Priya (or a teammate) removed it — “we always have a standard book.” There is no built-in before/after picture. She opens v3 and v4 in two windows and compares by eye.

It used to work. Someone saved v4. There is no native visual diff. You open both versions and compare by eye — or you buy Gearset.

Fix & prevent No native version comparison Automation Home work underway
v3 · last known good · Active last week
  • Get Standard Price Book
  • Create Renewal Opportunity
  • Email Account Owner
  • Fallback: use custom price book if standard is missing
v4 · Active now · Priya, Tuesday
  • Get Standard Price Book
  • Create Renewal Opportunity
  • Email Account Owner
  • Fallback removed — “we always have a standard book”

What Priya does

Keeps last-known-good copies in each sandbox. Stuffs notes in the description field. Real version control lives in GitHub or a paid tool. Two people editing at once overwrite each other.

Why it’s hard

An entire third-party category exists to sell this one missing screen. When users say “troubleshooting,” they often mean this too: tell me what changed.

9

She cannot be Jordan, in production, safely

Jordan’s deal, Jordan’s permissions, Tuesday 2:14 AM. Priya’s sandbox is a copy with different data, and she is a system admin. When she Debugs, it succeeds. Production keeps failing. She cannot run his interview as him, without saving the damage.

A sales user’s Closed Won doesn’t create a renewal. Their data and permissions aren’t in your sandbox. You cannot run their interview with rollback.

Diagnose Not shipped Adam White debugging PM brief
Production · 2:14 AM

Jordan (AE) closed Acme Renew · Price Book inactive · sharing rules hide the standard book · 18 Opportunities in the same batch.

Your sandbox · 9:40 AM

You are System Admin. Standard Price Book is active. Sample Opportunities don’t match the owner, the sharing, or the junction objects. Debug succeeds.

Why it’s hard

The method is: discover in production, then recreate the crime in a copy of the org. Live knock-on effects don’t reproduce. This “debug as another user, with undo” request has been on the debugging PM brief for years. It is not shipped.

10

Because none of that exists, they wire their own alarm

Serious teams add a red “if this fails, email Priya” branch onto every important recipe. That is home-made observability. Nothing later ties “this incident” to “this fix,” so the next person who turns off a Price Book can break it again.

Because detection is an email, teams build their own observability: error branches, extra “send email” actions, Splunk, Datadog. Nothing links the incident to the change that resolved it.

Fix & prevent Fault paths Ask Agentforce troubleshooting (beta)
Create Renewal Opportunity · fault connector
C
Create Renewal Opportunity
Create Records
FAULT
@
Email Priya the dump
Action · custom observability
SUCCESS
A
Email Account Owner
Action

What Priya does

Adds a fault connector by hand on every critical recipe. Still has no start-my-day health view. A new Ask Agentforce helper can explain a failure — inside Setup, in beta.

Why it’s hard

Monitoring is pull-by-tab or push-by-email. The next Price Book deactivation can fail silently until Jordan files another ticket. When people say “troubleshooting,” they often also mean watching and versioning — which is a different job on the official map, and the same morning for Priya.

Same Tuesday · a different morning

How headless would handle it

Priya still has the same 18 failed renewals. The difference is that the failure becomes one error object — impact, severity, failing step, root cause — that Slack, Claude, VS Code, and Flow Builder can all render. She does not start from an inbox dump. The canvas is still there when she wants to see the recipe. It is no longer the only door in.

Try the live Slack conversation in #flow-ops-oncall — click Block Kit buttons or type. Or watch the ~40s film across Slack, Claude, VS Code, and Flow Builder.

The rule

Headless does not replace Flow Builder. It means the recipe can be detected, explained, and proposed outside the canvas — then shown on the canvas when she needs to verify. Chat never writes to Production. The sandbox is where you rehearse. DevOps is what ships.

1 · Slack
The incident comes to her

Where she already is. One card: 18 records, High, the failing step named.

2 · Claude
Plain-language diagnosis

Pulls the failed run over MCP. Says what broke, and proposes a fix in plain language.

3 · VS Code
The same object, as code

A developer turns that production run into a red test, then a guard that stays in CI.

4 · Flow Builder
The recipe, on fire, then the fix

Run state drawn on the canvas. Proposed fallback is dashed until she accepts it into v5.

Slack — the alarm finds Priya

No 18 emails. Failures cross a threshold, INC-4821 opens itself, and posts to #flow-ops-oncall. Jordan’s deal is one of the 18. Priya can ask “what happened?” without leaving Slack.

#flow-ops-oncall · Slack
# flow-ops-oncall
F
FlowAPP9:02 AM
I spotted a failure in production.
● INC-4821 · High Create Renewal Opportunity v4
What: 18 Closed Won deals did not create a renewal after 2:14 AM
Failed at: Create Renewal Opportunity · Price Book lookup returned 0 records
Why: Standard Price Book was deactivated yesterday by Sam Chen
Jordan’s deal: Acme Renew · included in the 18
Explain what happened See it in Flow Builder Propose a fix

What changes for Priya

Detection is an incident, not an inbox. Severity, impact count, and the failing step are already on the card. “See it in Flow Builder” is a deep link to the same object — optional, not the only next step.

Same object

INC-4821 is what Claude and VS Code will load next. Slack is not a different truth. It is a different window on the same failure.

Claude — she asks in English

Priya pastes the incident, or Claude already has it via Salesforce MCP. She does not hunt boxes. She gets a diagnosis she can act on, and a proposed change in business language — before anything is saved.

Claude · INC-4821
Create Renewal Opportunity — failure
Why did Jordan’s Closed Won not create a renewal? INC-4821.
mcp · get_failed_run INC-4821 ok
mcp · get_flow Create_Renewal_Opportunity v4 ok
The recipe looks up the standard Price Book and then creates a renewal. Last night that catalog was deactivated (Sam Chen, 6:41 PM), so the lookup returned 0 records. Create Renewal then failed because it had no Price Book Id — 18 times.
Proposed change · not saved
  • Keep: when Opportunity is Closed Won
  • Keep: look up Standard Price Book
  • + If none found, use the custom “Renewals” Price Book
  • + Do not create if Price Book is still empty

What changes for Priya

The diagnosis is in her language: the catalog was turned off, so the lookup was empty. The fix is a proposed change she can approve or open on the canvas. Nothing writes to Production from chat.

Trust gate

This is the research bet: will she accept that proposal without seeing the flow? If she wants the picture, the next surface is Builder — with the proposal already marked.

VS Code — a developer keeps the proof

Devin, on-call in the IDE, loads the same INC-4821. Claude Code pulls the failed run and writes a test from Jordan’s real context, not a record Devin invented. When the fallback is in, the test that used to be red stays in CI so the next Price Book deactivation fails before deploy.

force-app/main/default/flows · VS Code
Create_Renewal_Opportunity.flow-meta.xmlinc4821.renewal.test.jsTerminal
// INC-4821 · from production run 2:14 AM · Opportunity 006Dn00000kR2aX
it('creates a renewal when the standard Price Book is inactive', async () => {
  await deactivateStandardPriceBook();
  const opp = loadProductionContext('INC-4821');
  const renewal = await runFlow('Create_Renewal_Opportunity', opp);
  expect(renewal.Pricebook2Id).not.toBeNull();
});
$ sf flow test run --file inc4821.renewal.test.js
FAIL INC-4821 reproduced · priceBookId = null
after fallback added —
PASS INC-4821 reproduced → now passing

What changes for Devin

The production failure is no longer gone. It is a fixture. Debug in VS Code is against that fixture, and the test remains as a regression guard — the missing “ship & prevent” beat from today.

Same object, third window

INC-4821 in Slack, the proposed change in Claude, and this test are three views of one run. He does not re-type Jordan’s Opportunity Id from the email.

Flow Builder — the recipe finally shows the fire

When Priya does open the canvas, it is not the blank healthy picture from this morning. The failed run is drawn on it: amber on the empty lookup, red on Create Renewal, grey after that. The proposed fallback is a dashed box — not saved — until she accepts it into v5 in the sandbox.

Flow Builder · Create Renewal Opportunity · v5 draft · sandbox
Create Renewal Opportunity · v5 draft · v4 still Active in Production
Proposed fix from Claude — nothing is saved yet INC-4821 · from #flow-ops-oncall 9:02 AM · 18 failed runs drawn below
S
Opportunity Closed Won
Start · 18 runs
G
Get Standard Price Book
Get Records · 0 records
HINT · deactivated by Sam Chen, yesterday 6:41 PM
Proposed
G
Fallback: Renewals Price Book
Get Records · added by Flow
C
Create Renewal Opportunity
Create Records · failed 18×
priceBookId was null · this is the throw
A
Email Account Owner
Not reached
Flow Automation Agent
Same fix as the proposal in Claude. v4 keeps running in Production until you accept this into the sandbox as v5.
+ Fallback lookup if standard Price Book is empty
+ Stop instead of throwing if still empty
· Trigger and Create Renewal unchanged

What she sees that she cannot see today

Run state on the canvas. The upstream empty lookup, not just the named failure. A HINT with who deactivated the catalog. A dashed proposal instead of a silent overwrite. Production is untouched.

Why the canvas is still in the story

Reviewers already said: once a flow is available to show, we gotta show it. Headless wins if she can understand and decide in Slack or Claude — then confirm here. The picture is the trust surface, not the only workplace.

If you only remember one thing

Today’s troubleshooting is detective work: an inbox instead of an incident, a picture that doesn’t show fire, a re-run that isn’t the original crime, and a new version saved on a guess. Headless is the same Tuesday with one error object — Slack brings it to Priya, Claude explains it, VS Code keeps the proof, Flow Builder draws the fire and the proposed fix.