Eliminating Null Reference Errors in Power Automate Flows
In this series: Power Automate gotchas
"The template language expression cannot be evaluated because property 'fieldname' doesn't exist."
If you have built more than a handful of Power Automate flows, you have seen that message at 9am on a Monday from a flow that worked fine in testing. It is the single most common runtime failure in the platform, and it almost always means the same thing: a field that was optional on the source record is suddenly missing, and your expression is referencing a JSON property that was never sent.
Why It Happens
When a Dataverse, SharePoint, or API response does not include a field — because it is null, empty, or optional — any expression referencing that field throws an error. The field literally does not exist in the JSON payload.
The Defensive Expressions
coalesce() — Your First Line of Defense
coalesce() returns the first non-null value from a list:
@coalesce(triggerOutputs()?['body/company'], 'No Company')
If company is null, the expression returns 'No Company' instead of crashing.
The Question Mark Operator
The ? in property access paths is critical. Compare:
❌ triggerOutputs()['body']['company'] — crashes if body or company is null
✅ triggerOutputs()?['body']?['company'] — returns null safely
Always use ?['property'] instead of ['property'] or .property notation.
if() for Conditional Logic
@if(
empty(triggerOutputs()?['body/phone']),
'N/A',
triggerOutputs()?['body/phone']
)
Combining for Nested Objects
For deeply nested fields that might not exist at any level:
@coalesce(
triggerOutputs()?['body']?['primarycontactid']?['fullname'],
'Unknown Contact'
)
Common Scenarios and Fixes
Lookup Fields
Lookup fields in Dataverse are objects, not simple values. A null lookup means the entire object is missing:
❌ triggerOutputs()?['body/_ownerid_value']
✅ coalesce(triggerOutputs()?['body/_ownerid_value'], '')
Array Access
Accessing an item in an array that might be empty:
❌ first(body('List_rows'))
✅ if(empty(body('List_rows')?['value']), null, first(body('List_rows')?['value']))
Or more concisely:
@first(coalesce(body('List_rows')?['value'], json('[]')))
HTTP Response Bodies
API responses might have different shapes based on status:
@if(
equals(outputs('HTTP')?['statusCode'], 200),
body('HTTP')?['data']?['result'],
'API Error'
)
Defensive Flow Design Patterns
1. Validate Early
Add a condition at the top of your flow that checks all required fields exist before processing:
@and(
not(empty(triggerOutputs()?['body/name'])),
not(empty(triggerOutputs()?['body/email'])),
greater(length(coalesce(triggerOutputs()?['body/items'], json('[]'))), 0)
)
If validation fails, terminate with a clear error message.
2. Use Compose for Intermediate Values
Instead of repeating long null-safe expressions, normalize values early:
- Compose
CustomerName:@coalesce(triggerOutputs()?['body/fullname'], 'Unknown') - Compose
CustomerEmail:@coalesce(triggerOutputs()?['body/emailaddress1'], '')
Then reference outputs('CustomerName') throughout the flow — clean and safe.
3. Schema Validation on HTTP Triggers
For flows triggered by HTTP requests, define a JSON schema on the trigger. Power Automate validates incoming requests against the schema and rejects malformed payloads before your flow logic even runs.
4. Do Not Pull Fields You Will Not Guard
On Dataverse triggers, Select columns is not just a performance tweak. An omitted column is absent from the payload, which is the same shape as a null. If you select emailaddress1 and later add an expression on telephone1, the run fails even when the record has a phone number.
Only select columns the flow reads, and wrap every one of them.
5. Skip the Run Entirely
A trigger condition is cheaper than a Compose + Condition + Terminate:
@not(empty(triggerOutputs()?['body/emailaddress1']))
Use this when missing data means "do nothing," not "do something else."
Key Takeaway
Use ?[] for every property access. Wrap anything that could be null in coalesce(). Validate required fields early. These three habits eliminate 95% of null reference errors and turn fragile flows into production-ready ones.
Keep reading
Retry Policies in Power Automate: What Actually Happens When an Action Fails
How Power Automate retry policies work, which errors they cover, how to configure them, and how to keep retries from duplicating side effects.
Resilient Power Automate: Retry Policies and Dead-Letter Patterns
Transient failures are normal in any flow that calls an API. The difference between a flow that self-heals and one that pages you at 2 a.m. is how you handle retries and the failures that stick.
15 Power Automate Expressions Every Maker Should Memorize
Memorize these Power Automate expressions to build faster flows, handle nulls, shape arrays, format dates, reduce action count, and debug WDL.
Calling the Dataverse Web API from Power Automate with the HTTP Action
Learn when to call the Dataverse Web API from Power Automate for actions, functions, batch requests, impersonation, row association, and binds.
Child Flows in Power Automate: Reuse, Pass Data, and Avoid Duplication
Use child flows in Power Automate to centralize reusable logic, pass typed inputs and outputs, handle errors, reduce duplication, and improve ALM.
Speeding Up Apply to Each: Concurrency, Filters, and Select in Power Automate
Speed up Power Automate Apply to each loops with concurrency, Filter array, Select, OData filters, pagination strategy, lower action counts, and safer runs.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.