Start free
Back to blog

DAX Measure Returns BLANK? A Diagnostic Flow for Power BI

A tactile calibration instrument comparing a plausible output with a silent missing result marked for verification

When a DAX measure returns BLANK, first determine whether the base
rows are absent, the aggregation is blank, or the final formula
deliberately produces blank. Do not start with
COALESCE ( [Measure], 0 ); that can hide a broken
relationship, missing prior period, or invalid business state.

Use this diagnostic flow from the model outward.

Step 1: Count
the rows available to the measure

Create a temporary measure against the fact table:

Debug Fact Rows =
COUNTROWS ( Sales )

Place it in the same visual and filter state as the blank
measure.

  • If the count is zero, investigate filter context and
    relationships.
  • If rows exist, inspect the input column and aggregation.
  • If the count changes correctly but the measure stays blank, debug
    the formula branch by branch.

This is more useful than staring at the final expression.

Step 2: Test the base
aggregation

Suppose the measure is:

Margin Percent =
DIVIDE ( [Margin], [Sales Amount] )

Add [Margin] and [Sales Amount] to the
visual separately.

Then go one level lower:

Debug Sales Amount =
SUM ( Sales[SalesAmount] )
Debug Nonblank Amount Rows =
COUNT ( Sales[SalesAmount] )

Rows can exist while the numeric column contains only blanks. A row
count and a nonblank-value count answer different questions.

Step 3: Expose the
current filter context

Show what the measure can see:

Debug Categories =
CONCATENATEX (
    VALUES ( Product[Category] ),
    Product[Category],
    ", "
)
Debug Date Range =
FORMAT ( MIN ( 'Date'[Date] ), "yyyy-mm-dd" )
    & " to "
    & FORMAT ( MAX ( 'Date'[Date] ), "yyyy-mm-dd" )

Use the exact columns referenced by the visual and slicer. A field
that looks equivalent may come from a disconnected table or a different
date role.

If the same measure works in a card but fails in a matrix row, the
matrix adds filter context that removes all matching rows or sends the
formula down a different branch.

Step 4: Trace the
relationship path

A dimension filter reaches the fact table only through active
relationships.

Test:

Debug Visible Products =
COUNTROWS ( VALUES ( Product[ProductKey] ) )
Debug Visible Sales Rows =
COUNTROWS ( Sales )

Change a Product slicer.

  • If visible products change but Sales rows do not, the relationship
    path is broken or intentionally disconnected.
  • If both change to zero, the selection may have no matching fact
    rows.
  • If Sales rows change correctly, the blank is probably inside the
    measure.

Use the Power BI
relationship checklist
before adding virtual relationships or
bidirectional filtering.

Step 5: Check
single-value assumptions

SELECTEDVALUE returns its alternate result when the
context contains zero or more than one distinct value:

Selected Currency =
SELECTEDVALUE ( Currency[Code] )

Debug it with:

Debug Currency Count =
COUNTROWS ( VALUES ( Currency[Code] ) )

If the count is not one, the blank is expected.

Provide an explicit alternate only when the business rule supports
it:

Selected Currency =
SELECTEDVALUE ( Currency[Code], "Multiple" )

Do not use a fallback that silently chooses one currency. The SELECTEDVALUE returns blank
guide
covers all seven checks.

Step 6: Check division and
arithmetic

DIVIDE returns BLANK by default when its denominator is
zero or blank:

Margin Percent =
DIVIDE ( [Margin], [Sales Amount] )

That is often safer than forcing zero. A zero margin percentage says
there was a valid denominator and no margin; BLANK can say the
percentage is undefined.

If the report specification requires zero:

Margin Percent Display =
COALESCE (
    DIVIDE ( [Margin], [Sales Amount] ),
    0
)

Keep the semantic measure and display decision conceptually separate.
Microsoft
recommends retaining BLANKs when they efficiently exclude irrelevant
groupings
, rather than converting every missing result to a dense
zero.

Step 7: Inspect IF and
SWITCH branches

A measure can return BLANK because no branch matches:

Status Value =
SWITCH (
    SELECTEDVALUE ( Status[Name] ),
    "Open", [Open Amount],
    "Closed", [Closed Amount]
)

With no final else expression, unmatched states return BLANK.

Add a temporary diagnostic:

Status Value Debug =
SWITCH (
    SELECTEDVALUE ( Status[Name] ),
    "Open", [Open Amount],
    "Closed", [Closed Amount],
    -999999
)

If the sentinel appears, the issue is branch selection. Remove the
sentinel after testing.

Also inspect nested IF conditions,
HASONEVALUE, ISINSCOPE, and variables that
capture a blank earlier than expected.

Step 8: Verify date coverage

Time-intelligence measures return BLANK when the requested comparison
period contains no dates or no fact rows.

For prior-year sales:

Sales Last Year =
CALCULATE (
    [Sales Amount],
    SAMEPERIODLASTYEAR ( 'Date'[Date] )
)

Check:

  • whether the date table includes the prior-year dates;
  • whether Sales has matching rows;
  • whether the Date relationship is active;
  • whether the visual uses the Date table; and
  • whether another filter removes the comparison period.

Use the focused SAMEPERIODLASTYEAR blank
checklist
for that case, or the date-table guide
for broader time-intelligence failures.

Step 9: Find
filters the measure removes or adds

The measure may create an impossible intersection:

Red Bike Sales =
CALCULATE (
    [Sales Amount],
    Product[Color] = "Red",
    Product[Category] = "Bikes"
)

If the model contains no red bikes, BLANK is correct.

Or a nested measure may remove the context needed for a lookup:

CALCULATE (
    [Some Measure],
    REMOVEFILTERS ( Customer )
)

Expose filters with VALUES, count fact rows after each
modifier, and add one filter argument at a time.

Step 10:
Decide whether BLANK is the correct result

BLANK is often meaningful:

  • no rows match;
  • a ratio is undefined;
  • no single selection exists;
  • no prior period exists;
  • a hierarchy level should not display the measure;
  • the calculation is not applicable.

Only convert BLANK to zero when zero is a truthful numeric statement.
The BLANK vs 0 guide provides the
decision rules.

A compact diagnostic measure
set

Keep these temporary measures nearby:

Debug Rows = COUNTROWS ( Sales )
Debug Keys = COUNTROWS ( VALUES ( Sales[OrderKey] ) )
Debug Min Date = MIN ( 'Date'[Date] )
Debug Max Date = MAX ( 'Date'[Date] )
Debug Selection Count =
COUNTROWS ( VALUES ( Selector[Value] ) )

They answer five questions: Are rows present? At what grain? In which
period? Under how many selections?

Frequently asked questions

Why
does my measure return BLANK in a table but work in a card?

The table row adds filter context. That context may remove all
matching fact rows, produce multiple values where one was expected, or
trigger an ISINSCOPE/IF branch.

Why does adding 0 make
the value appear?

Arithmetic or COALESCE converts BLANK to a numeric
result. That changes display behavior but does not explain why the
original measure was blank.

Can a broken relationship
cause BLANK?

Yes. A filter can fail to reach the fact table, or a transitioned key
can match no rows. Count visible fact rows under the same dimension
selection.

Where can I isolate the
failure?

Paste the measure and its base dependencies into the DAX
playground
. Keep the row-count and selection-count measures visible
until the first blank-producing step is identified.

Done reading?

Put it into reps — pick a challenge.

Start practicing More posts