<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: PBIDocs</title>
    <description>The latest articles on DEV Community by PBIDocs (@pbidocs).</description>
    <link>https://dev.to/pbidocs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4079301%2F80e78974-a01f-4cb2-9bbe-313106026c17.png</url>
      <title>DEV Community: PBIDocs</title>
      <link>https://dev.to/pbidocs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pbidocs"/>
    <language>en</language>
    <item>
      <title>Power Query Error: We Couldn't Convert to Number (or Date)</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Tue, 25 Aug 2026 20:07:29 +0000</pubDate>
      <link>https://dev.to/pbidocs/power-query-error-we-couldnt-convert-to-number-or-date-3poc</link>
      <guid>https://dev.to/pbidocs/power-query-error-we-couldnt-convert-to-number-or-date-3poc</guid>
      <description>&lt;p&gt;The instinct is to assume the source data is just messy. Sometimes it is — but just as often, the value is perfectly valid and Power Query is parsing it under the wrong assumptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step One: Isolate the Actual Bad Rows
&lt;/h2&gt;

&lt;p&gt;Don't guess. After the failing type-conversion step, right-click the column header and choose &lt;strong&gt;Keep Errors&lt;/strong&gt; — this filters the table down to only the rows that failed, instead of scrolling to find them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full table (10,000 rows)
        |
        | Keep Errors, after the type conversion step
        |
Just the rows that failed (often a handful, sometimes just one pattern)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 1: A Locale Mismatch on the Decimal Separator
&lt;/h2&gt;

&lt;p&gt;The most common cause with numbers specifically. &lt;code&gt;1.234,56&lt;/code&gt; is a perfectly valid number in most of continental Europe — comma as the decimal separator, period as the thousands separator. Power Query, using a different default locale, reads that same text as &lt;code&gt;1.234&lt;/code&gt; followed by garbage, and fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Value in source: "1.234,56"   (intended: one thousand, two hundred thirty-four point five six)
Parsed with US locale (period = decimal): fails or misreads entirely
Parsed with the correct locale: 1234.56
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; convert with an explicit locale rather than the default. Right-click the column, &lt;strong&gt;Transform &amp;gt; Using Locale&lt;/strong&gt;, and pick the locale the source data actually uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Changed Type with Locale" = Table.TransformColumnTypes(
    Source, {{"Amount", type number}}, "de-DE"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 2: An Ambiguous Date Format — and the Silent Version Is Worse
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;13/04/2026&lt;/code&gt; fails loudly, because no locale reads month 13 as valid — that's the easy case. The genuinely dangerous version is a date like &lt;code&gt;03/04/2026&lt;/code&gt;, which is valid in &lt;em&gt;both&lt;/em&gt; &lt;code&gt;DD/MM/YYYY&lt;/code&gt; and &lt;code&gt;MM/DD/YYYY&lt;/code&gt; — one means March 4th, the other April 3rd. If the locale assumption is wrong, this parses &lt;strong&gt;successfully into the wrong date&lt;/strong&gt;, with no error at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"03/04/2026" with DD/MM locale -&amp;gt; April 3rd
"03/04/2026" with MM/DD locale -&amp;gt; March 4th

Both "succeed." Only one is correct. Nothing flags the other.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; the same locale-aware conversion as Cause 1 — but critically, this cause won't show up in a &lt;strong&gt;Keep Errors&lt;/strong&gt; check, since nothing errors. If dates look off by a matter of days or months in a way that smells like this, check the locale explicitly rather than trusting the absence of an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Changed Type with Locale" = Table.TransformColumnTypes(
    Source, {{"OrderDate", type date}}, "en-GB"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 3: A Stray Non-Numeric Value
&lt;/h2&gt;

&lt;p&gt;The straightforward version: a column that's otherwise numbers has a handful of rows containing &lt;code&gt;"N/A"&lt;/code&gt;, &lt;code&gt;"TBD"&lt;/code&gt;, &lt;code&gt;"-"&lt;/code&gt;, or an empty string — often placeholders someone typed in a spreadsheet for "not applicable yet."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Amount
1200
850
N/A       &amp;lt;- this row fails the whole conversion
430
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; replace the placeholder with &lt;code&gt;null&lt;/code&gt; (or a real default) before converting type, not after.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Replaced Value" = Table.ReplaceValue(
    Source, "N/A", null, Replacer.ReplaceValue, {"Amount"}
),
#"Changed Type" = Table.TransformColumnTypes(#"Replaced Value", {{"Amount", type number}})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 4: Hidden Whitespace or Non-Breaking Spaces
&lt;/h2&gt;

&lt;p&gt;Data that's passed through a PDF export, a copy-paste from a web page, or certain legacy systems can carry non-breaking space characters or trailing whitespace that look identical to a normal space — or nothing at all — but aren't.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"1234 "   (trailing space, invisible)
"1234"    (clean)

Look identical. Only one converts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;Text.Trim&lt;/code&gt; before the type conversion — but note plain &lt;code&gt;Text.Trim&lt;/code&gt; doesn't always catch a non-breaking space (&lt;code&gt;Unicode 00A0&lt;/code&gt;), which sometimes needs an explicit replace first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Cleaned" = Table.TransformColumns(
    Source, {{"Amount", each Text.Trim(Text.Replace(_, "#(00A0)", " "))}}
),
#"Changed Type" = Table.TransformColumnTypes(#"Cleaned", {{"Amount", type number}})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://pbidocs.com/docs/power-query/m-language#core-data-types" rel="noopener noreferrer"&gt;M Language&lt;/a&gt; for more on M's text and type functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fixing one bad value without checking for others.&lt;/strong&gt; Replacing the specific value from the error message feels done, but the same source often has more than one placeholder pattern (&lt;code&gt;"N/A"&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;"TBD"&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; a blank) — a single replace fixes only the one that happened to error first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trusting a date just because it didn't error.&lt;/strong&gt; As Cause 2 shows, the silent locale mismatch never produces an error to catch — the only defense is checking the locale explicitly, not waiting for Power Query to complain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixing the symptom in Power Query without asking why the source exports inconsistent formats.&lt;/strong&gt; If the same source keeps producing this on every refresh, the more durable fix is often upstream — a consistent export format or a documented locale — not a growing pile of &lt;code&gt;Table.ReplaceValue&lt;/code&gt; steps.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pbidocs.com/blog/couldnt-convert-to-number-date-error" rel="noopener noreferrer"&gt;PBIDocs&lt;/a&gt; — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>powerquery</category>
      <category>dataengineering</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>Why Did My Power Query Refresh Suddenly Get Slower?</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Tue, 25 Aug 2026 20:06:00 +0000</pubDate>
      <link>https://dev.to/pbidocs/why-did-my-power-query-refresh-suddenly-get-slower-1enb</link>
      <guid>https://dev.to/pbidocs/why-did-my-power-query-refresh-suddenly-get-slower-1enb</guid>
      <description>&lt;p&gt;There's no error message for this one — the refresh just finishes. It's just slower. A query that used to take ten seconds now takes ten minutes, nothing was obviously changed, and there's nothing in the UI shouting about why.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last week: refresh in 8 seconds
This week: refresh in 6 minutes
No error. No warning. Nothing "broke" in the way an error implies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This almost always means &lt;a href="https://pbidocs.com/docs/power-query/query-folding" rel="noopener noreferrer"&gt;query folding&lt;/a&gt; stopped somewhere in the query — silently, since a broken fold isn't an error condition, just a much slower execution path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Actually Check
&lt;/h2&gt;

&lt;p&gt;Right-click any step in &lt;strong&gt;Applied Steps&lt;/strong&gt; and look at &lt;strong&gt;View Native Query&lt;/strong&gt;. If it's available, everything up to and including that step is still folding to the source. The moment it's grayed out, folding has already stopped at or before that step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source          -&amp;gt; View Native Query available
Filtered Rows   -&amp;gt; View Native Query available
Added Custom    -&amp;gt; View Native Query grayed out   &amp;lt;- folding stopped here
Renamed Columns -&amp;gt; still grayed out (nothing after a break can fold again)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Work backward from the last step, checking each one, until the option is available again — that's the exact boundary where folding broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: A New Step Was Added in the Wrong Position
&lt;/h2&gt;

&lt;p&gt;The most common cause of a query that "used to be fast." Adding a new step doesn't insert it at the end of a logical plan — it inserts it exactly where Applied Steps shows it, and everything downstream inherits whatever folding state that step leaves behind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:  Source -&amp;gt; Filter (folds) -&amp;gt; Select Columns (folds) -&amp;gt; Changed Type (folds)
After:   Source -&amp;gt; Filter (folds) -&amp;gt; Added Custom Column (doesn't fold) -&amp;gt; Select Columns -&amp;gt; Changed Type
                                            ^
                                   everything from here runs locally now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; move steps that can't fold (custom columns, complex conditional logic) as late in the sequence as possible — after filtering and column selection, not before. See &lt;a href="https://pbidocs.com/docs/power-query/query-folding#ordering-steps-to-preserve-folding" rel="noopener noreferrer"&gt;Ordering Steps to Preserve Folding&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: A Custom Column With Row-by-Row Logic
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Table.AddColumn&lt;/code&gt; with an &lt;code&gt;each&lt;/code&gt; expression referencing M functions that have no equivalent in the source's native query language can't be translated back — the entire step, and everything after it, has to run locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Added Custom" = Table.AddColumn(
    Source, "Flag",
    each if Text.Contains([Notes], "urgent") then "Y" else "N"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is often unavoidable — not every transformation has a source-side equivalent — but it's worth knowing it's the trade being made, and placing it as late as possible so it affects the smallest number of rows and downstream steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: Table.Buffer in the Wrong Spot
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Table.Buffer()&lt;/code&gt; forces full materialization into memory — useful for stabilizing a volatile source, but it also ends folding immediately at that point, even if every step before and after it would otherwise fold cleanly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source (folds) -&amp;gt; Filter (folds) -&amp;gt; Table.Buffer -&amp;gt; Group (doesn't fold, runs locally)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://pbidocs.com/docs/power-query/table-buffer#the-real-cost-tablebuffer-breaks-query-folding" rel="noopener noreferrer"&gt;Table.Buffer&lt;/a&gt; — this one is easy to miss specifically because it doesn't look like a transformation at all, just a performance-sounding function name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: A Merge Against a Non-Folding Source
&lt;/h2&gt;

&lt;p&gt;Merging a folding query (say, a SQL table) with a query from a source that can't fold (an Excel file, a CSV, an API call) means the combined result can't be pushed back to a single source's native query language — there's no one engine that understands both halves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQL query (folds) + Excel query (never folds)
        |
        merged
        |
Result: doesn't fold, regardless of how well the SQL side folds alone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is sometimes unavoidable (the data genuinely lives in two different places), but it's worth knowing the merge itself is where folding ends, not something to debug further downstream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Assuming a slow refresh means the source is just slow.&lt;/strong&gt; It's easy to blame the database or the network before checking whether the query itself stopped folding — check &lt;strong&gt;View Native Query&lt;/strong&gt; before escalating to infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding steps in whatever order feels natural, not a folding-aware order.&lt;/strong&gt; Applied Steps records the order things were built, not necessarily the order they should stay in — reordering after the fact is normal and often the entire fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not re-checking folding after adding new steps to a previously-fast query.&lt;/strong&gt; A query that folded perfectly last month can silently stop folding the moment one new step is added — checking once at the start isn't enough if the query keeps evolving.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pbidocs.com/blog/refresh-suddenly-slow-query-folding-broke" rel="noopener noreferrer"&gt;PBIDocs&lt;/a&gt; — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>powerquery</category>
      <category>performance</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>"Why Did My Power Query Refresh Suddenly Get Slower?"</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Tue, 25 Aug 2026 20:02:12 +0000</pubDate>
      <link>https://dev.to/pbidocs/why-did-my-power-query-refresh-suddenly-get-slower-pm4</link>
      <guid>https://dev.to/pbidocs/why-did-my-power-query-refresh-suddenly-get-slower-pm4</guid>
      <description>&lt;p&gt;There's no error message for this one — the refresh just finishes. It's just slower. A query that used to take ten seconds now takes ten minutes, nothing was obviously changed, and there's nothing in the UI shouting about why.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last week: refresh in 8 seconds
This week: refresh in 6 minutes
No error. No warning. Nothing "broke" in the way an error implies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This almost always means &lt;a href="https://pbidocs.com/docs/power-query/query-folding" rel="noopener noreferrer"&gt;query folding&lt;/a&gt; stopped somewhere in the query — silently, since a broken fold isn't an error condition, just a much slower execution path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Actually Check
&lt;/h2&gt;

&lt;p&gt;Right-click any step in &lt;strong&gt;Applied Steps&lt;/strong&gt; and look at &lt;strong&gt;View Native Query&lt;/strong&gt;. If it's available, everything up to and including that step is still folding to the source. The moment it's grayed out, folding has already stopped at or before that step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source          -&amp;gt; View Native Query available
Filtered Rows   -&amp;gt; View Native Query available
Added Custom    -&amp;gt; View Native Query grayed out   &amp;lt;- folding stopped here
Renamed Columns -&amp;gt; still grayed out (nothing after a break can fold again)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Work backward from the last step, checking each one, until the option is available again — that's the exact boundary where folding broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: A New Step Was Added in the Wrong Position
&lt;/h2&gt;

&lt;p&gt;The most common cause of a query that "used to be fast." Adding a new step doesn't insert it at the end of a logical plan — it inserts it exactly where Applied Steps shows it, and everything downstream inherits whatever folding state that step leaves behind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:  Source -&amp;gt; Filter (folds) -&amp;gt; Select Columns (folds) -&amp;gt; Changed Type (folds)
After:   Source -&amp;gt; Filter (folds) -&amp;gt; Added Custom Column (doesn't fold) -&amp;gt; Select Columns -&amp;gt; Changed Type
                                            ^
                                   everything from here runs locally now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; move steps that can't fold (custom columns, complex conditional logic) as late in the sequence as possible — after filtering and column selection, not before. See &lt;a href="https://pbidocs.com/docs/power-query/query-folding#ordering-steps-to-preserve-folding" rel="noopener noreferrer"&gt;Ordering Steps to Preserve Folding&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 2: A Custom Column With Row-by-Row Logic
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Table.AddColumn&lt;/code&gt; with an &lt;code&gt;each&lt;/code&gt; expression referencing M functions that have no equivalent in the source's native query language can't be translated back — the entire step, and everything after it, has to run locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Added Custom" = Table.AddColumn(
    Source, "Flag",
    each if Text.Contains([Notes], "urgent") then "Y" else "N"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is often unavoidable — not every transformation has a source-side equivalent — but it's worth knowing it's the trade being made, and placing it as late as possible so it affects the smallest number of rows and downstream steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 3: Table.Buffer in the Wrong Spot
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Table.Buffer()&lt;/code&gt; forces full materialization into memory — useful for stabilizing a volatile source, but it also ends folding immediately at that point, even if every step before and after it would otherwise fold cleanly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source (folds) -&amp;gt; Filter (folds) -&amp;gt; Table.Buffer -&amp;gt; Group (doesn't fold, runs locally)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://pbidocs.com/docs/power-query/table-buffer#the-real-cost-tablebuffer-breaks-query-folding" rel="noopener noreferrer"&gt;Table.Buffer&lt;/a&gt; — this one is easy to miss specifically because it doesn't look like a transformation at all, just a performance-sounding function name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: A Merge Against a Non-Folding Source
&lt;/h2&gt;

&lt;p&gt;Merging a folding query (say, a SQL table) with a query from a source that can't fold (an Excel file, a CSV, an API call) means the combined result can't be pushed back to a single source's native query language — there's no one engine that understands both halves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQL query (folds) + Excel query (never folds)
        |
        merged
        |
Result: doesn't fold, regardless of how well the SQL side folds alone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is sometimes unavoidable (the data genuinely lives in two different places), but it's worth knowing the merge itself is where folding ends, not something to debug further downstream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Assuming a slow refresh means the source is just slow.&lt;/strong&gt; It's easy to blame the database or the network before checking whether the query itself stopped folding — check &lt;strong&gt;View Native Query&lt;/strong&gt; before escalating to infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding steps in whatever order feels natural, not a folding-aware order.&lt;/strong&gt; Applied Steps records the order things were built, not necessarily the order they should stay in — reordering after the fact is normal and often the entire fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not re-checking folding after adding new steps to a previously-fast query.&lt;/strong&gt; A query that folded perfectly last month can silently stop folding the moment one new step is added — checking once at the start isn't enough if the query keeps evolving.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pbidocs.com/blog/refresh-suddenly-slow-query-folding-broke" rel="noopener noreferrer"&gt;PBIDocs&lt;/a&gt; — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>powerquery</category>
      <category>performance</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>"Power Query Error: Formula.Firewall and Privacy Level Errors"</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Sun, 16 Aug 2026 15:46:19 +0000</pubDate>
      <link>https://dev.to/pbidocs/power-query-error-formulafirewall-and-privacy-level-errors-3oo3</link>
      <guid>https://dev.to/pbidocs/power-query-error-formulafirewall-and-privacy-level-errors-3oo3</guid>
      <description>&lt;p&gt;This isn't a syntax error or a bug in the query — it's Power Query's &lt;strong&gt;Formula Firewall&lt;/strong&gt; refusing to combine data from more than one source until it knows whether that's actually safe. Combining a private/organizational source with a public one (an internal database and a public web API, for example) can leak data from one into the other; the firewall blocks it by default rather than guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Exists
&lt;/h2&gt;

&lt;p&gt;Every data source in Power Query has a &lt;strong&gt;privacy level&lt;/strong&gt; — Public, Organizational, or Private — set the first time it's connected to. When a query's steps end up needing to send data from one source &lt;em&gt;into&lt;/em&gt; a call against a different source, Power Query checks whether the privacy levels involved allow that combination.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pbidocs.com/blog/formula-firewall-privacy-level-error" rel="noopener noreferrer"&gt;PBIDocs&lt;/a&gt; — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>powerbi</category>
      <category>powerquery</category>
      <category>dataengineering</category>
      <category>troubleshooting</category>
    </item>
    <item>
      <title>"Power BI Error: The Key Didn't Match Any Rows in the Table"</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Sun, 16 Aug 2026 15:45:17 +0000</pubDate>
      <link>https://dev.to/pbidocs/power-bi-error-the-key-didnt-match-any-rows-in-the-table-556a</link>
      <guid>https://dev.to/pbidocs/power-bi-error-the-key-didnt-match-any-rows-in-the-table-556a</guid>
      <description>&lt;p&gt;description: "The key didn't match any rows in the table" comes from LOOKUPVALUE finding zero matches, not too many. Here's how to find why, and the four usual causes.&lt;br&gt;
tags: powerbi, dax, troubleshooting, tutorial&lt;/p&gt;
&lt;h2&gt;
  
  
  canonical_url: &lt;a href="https://pbidocs.com/blog/key-didnt-match-any-rows-error" rel="noopener noreferrer"&gt;https://pbidocs.com/blog/key-didnt-match-any-rows-error&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The full error reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The key didn't match any rows in the table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the opposite problem from a &lt;a href="https://pbidocs.com/blog/column-contains-duplicate-value-error" rel="noopener noreferrer"&gt;duplicate value error&lt;/a&gt;. That one means &lt;code&gt;LOOKUPVALUE()&lt;/code&gt; (or a relationship) found &lt;em&gt;too many&lt;/em&gt; matching rows. This one means it found &lt;em&gt;zero&lt;/em&gt; — the search value you gave it doesn't exist anywhere in the target column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product Category =
LOOKUPVALUE(
    DimProduct[Category],
    DimProduct[ProductKey], FactSales[ProductKey]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If some &lt;code&gt;ProductKey&lt;/code&gt; in &lt;code&gt;FactSales&lt;/code&gt; has no matching row in &lt;code&gt;DimProduct&lt;/code&gt;, this measure throws that exact error for those rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step One: Find Which Values Are Actually Missing
&lt;/h2&gt;

&lt;p&gt;Before guessing at a cause, find the specific values that don't match. A quick way: build a calculated column that checks membership directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Key Exists =
CONTAINS(DimProduct, DimProduct[ProductKey], FactSales[ProductKey])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filter this to &lt;code&gt;FALSE&lt;/code&gt; in a table visual alongside &lt;code&gt;FactSales[ProductKey]&lt;/code&gt;, and you have the exact list of keys causing the problem — the starting point for figuring out which of the causes below actually applies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 1: A Data Type Mismatch
&lt;/h2&gt;

&lt;p&gt;The single most common cause. If &lt;code&gt;FactSales[ProductKey]&lt;/code&gt; is text and &lt;code&gt;DimProduct[ProductKey]&lt;/code&gt; is a whole number (or vice versa), &lt;code&gt;LOOKUPVALUE()&lt;/code&gt; won't match them even when the underlying values "look" the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FactSales[ProductKey] = "1001"   (text)
DimProduct[ProductKey] = 1001    (whole number)

LOOKUPVALUE searching for "1001" in a column of numbers -&amp;gt; no match
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; make both columns the same type before the relationship or lookup is built — usually in Power Query, on whichever side came in with the wrong type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Changed Type" = Table.TransformColumnTypes(
    Source,
    {{"ProductKey", Int64.Type}}
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 2: Trailing Whitespace or Case Differences
&lt;/h2&gt;

&lt;p&gt;For text keys specifically, invisible whitespace or inconsistent casing breaks an exact match even though the values look identical in a visual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FactSales[SKU] = "AB-1001 "   (trailing space)
DimProduct[SKU] = "AB-1001"

Look identical when displayed. Not equal to LOOKUPVALUE.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; clean both sides with &lt;code&gt;Text.Trim&lt;/code&gt; (and &lt;code&gt;Text.Upper&lt;/code&gt;/&lt;code&gt;Text.Lower&lt;/code&gt; if casing is inconsistent) in Power Query before the values are used as keys — see &lt;a href="https://pbidocs.com/docs/power-query/m-language" rel="noopener noreferrer"&gt;M Language&lt;/a&gt; for these functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Trimmed Text" = Table.TransformColumns(
    Source,
    {{"SKU", Text.Trim}}
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cause 3: The Value Genuinely Doesn't Exist Yet
&lt;/h2&gt;

&lt;p&gt;Sometimes it's not a data quality bug — the fact table legitimately references something the dimension table doesn't have. A product was discontinued and removed from &lt;code&gt;DimProduct&lt;/code&gt;, but historical &lt;code&gt;FactSales&lt;/code&gt; rows still reference its old key. Or a new product started selling before the dimension table's daily refresh caught up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FactSales (2024-2026, includes discontinued products)
DimProduct (current catalog only, discontinued products removed)

ProductKey 1001 sold in 2024, but DimProduct no longer has it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; this is a referential integrity gap, not a formula bug. Either keep discontinued/historical members in the dimension table (with a flag like &lt;code&gt;IsActive = FALSE&lt;/code&gt; instead of deleting the row), or add a placeholder row for exactly this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DimProduct
ProductKey | ProductName
1001       | Trail Runner Tire
1002       | Commuter Helmet
-1         | Unknown Product      &amp;lt;- catches orphaned keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://pbidocs.com/docs/modeling/dimension-tables" rel="noopener noreferrer"&gt;Dimension Tables&lt;/a&gt; for why dimension tables are built to be the complete, authoritative list a fact table can always join against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause 4: A Default Value Was Never Set
&lt;/h2&gt;

&lt;p&gt;Independent of fixing the underlying data, &lt;code&gt;LOOKUPVALUE()&lt;/code&gt; has an optional final argument specifically for this situation — a value to return instead of erroring when nothing matches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product Category =
LOOKUPVALUE(
    DimProduct[Category],
    DimProduct[ProductKey], FactSales[ProductKey],
    "Unknown"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn't fix &lt;em&gt;why&lt;/em&gt; the key is missing, but it stops one bad row from breaking the entire calculation while the underlying cause gets investigated. See &lt;a href="https://pbidocs.com/docs/dax/lookupvalue" rel="noopener noreferrer"&gt;LOOKUPVALUE&lt;/a&gt; for the full syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Adding a default value without investigating why.&lt;/strong&gt; &lt;code&gt;LOOKUPVALUE(..., "Unknown")&lt;/code&gt; makes the error go away, but if the missing keys represent a real data quality problem (like Cause 3), silently defaulting to "Unknown" can hide it indefinitely instead of fixing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assuming it's always a relationship problem.&lt;/strong&gt; This specific error comes from &lt;code&gt;LOOKUPVALUE()&lt;/code&gt; and similar functions evaluated directly — not from a standard modeled relationship, which handles unmatched keys differently (rows just don't appear, or appear under a blank member, rather than throwing this error). Don't go looking in Model view for a broken relationship when the actual cause is a DAX formula.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixing the symptom on only one side.&lt;/strong&gt; A type or whitespace mismatch usually needs fixing wherever the &lt;em&gt;bad&lt;/em&gt; data originates, not just patching the lookup formula — otherwise the same mismatch reappears the next time new data loads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The specific missing keys have been identified (via a membership check), not just guessed at.&lt;/li&gt;
&lt;li&gt;Data types match exactly between the two columns being compared.&lt;/li&gt;
&lt;li&gt;Text keys are trimmed and case-normalized before being used as lookup keys.&lt;/li&gt;
&lt;li&gt;If the value is legitimately absent from the dimension table, that's addressed as a modeling decision (keep historical rows, or add a placeholder), not just papered over with a default.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pbidocs.com/blog/key-didnt-match-any-rows-error" rel="noopener noreferrer"&gt;PBIDocs&lt;/a&gt; — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>database</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>"Power BI Error: The Key Didn't Match Any Rows in the Table"</title>
      <dc:creator>PBIDocs</dc:creator>
      <pubDate>Sat, 15 Aug 2026 22:14:50 +0000</pubDate>
      <link>https://dev.to/pbidocs/power-bi-error-the-key-didnt-match-any-rows-in-the-table-3fmi</link>
      <guid>https://dev.to/pbidocs/power-bi-error-the-key-didnt-match-any-rows-in-the-table-3fmi</guid>
      <description>&lt;p&gt;tags: powerbi, dax, troubleshooting, tutorial&lt;/p&gt;

&lt;h2&gt;
  
  
  canonical_url: &lt;a href="https://pbidocs.com/blog/key-didnt-match-any-rows-error" rel="noopener noreferrer"&gt;https://pbidocs.com/blog/key-didnt-match-any-rows-error&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The full error reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The key didn't match any rows in the table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the opposite problem from a &lt;a href="https://pbidocs.com/blog/column-contains-duplicate-value-error" rel="noopener noreferrer"&gt;duplicate value error&lt;/a&gt;. That one means &lt;code&gt;LOOKUPVALUE()&lt;/code&gt; (or a relationship) found &lt;em&gt;too many&lt;/em&gt; matching rows. This one means it found &lt;em&gt;zero&lt;/em&gt; — the search value you gave it doesn't exist anywhere in the target column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product Category =
LOOKUPVALUE(
    DimProduct[Category],
    DimProduct[ProductKey], FactSales[ProductKey]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step One: Find Which Values Are Actually Missing&lt;br&gt;
Before guessing at a cause, find the specific values that don't match. A quick way: build a calculated column that checks membership directly.&lt;/p&gt;

&lt;p&gt;Key Exists =&lt;br&gt;
CONTAINS(DimProduct, DimProduct[ProductKey], FactSales[ProductKey])&lt;br&gt;
Filter this to FALSE in a table visual alongside FactSales[ProductKey], and you have the exact list of keys causing the problem — the starting point for figuring out which of the causes below actually applies.&lt;/p&gt;

&lt;p&gt;Cause 1: A Data Type Mismatch&lt;br&gt;
The single most common cause. If FactSales[ProductKey] is text and DimProduct[ProductKey] is a whole number (or vice versa), LOOKUPVALUE() won't match them even when the underlying values "look" the same.&lt;/p&gt;

&lt;p&gt;FactSales[ProductKey] = "1001"   (text)&lt;br&gt;
DimProduct[ProductKey] = 1001    (whole number)&lt;/p&gt;

&lt;p&gt;LOOKUPVALUE searching for "1001" in a column of numbers -&amp;gt; no match&lt;br&gt;
Fix: make both columns the same type before the relationship or lookup is built — usually in Power Query, on whichever side came in with the wrong type.&lt;/p&gt;

&lt;h1&gt;
  
  
  "Changed Type" = Table.TransformColumnTypes(
&lt;/h1&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source,
{{"ProductKey", Int64.Type}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;)&lt;br&gt;
Cause 2: Trailing Whitespace or Case Differences&lt;br&gt;
For text keys specifically, invisible whitespace or inconsistent casing breaks an exact match even though the values look identical in a visual.&lt;/p&gt;

&lt;p&gt;FactSales[SKU] = "AB-1001 "   (trailing space)&lt;br&gt;
DimProduct[SKU] = "AB-1001"&lt;/p&gt;

&lt;p&gt;Look identical when displayed. Not equal to LOOKUPVALUE.&lt;br&gt;
Fix: clean both sides with Text.Trim (and Text.Upper/Text.Lower if casing is inconsistent) in Power Query before the values are used as keys — see M Language for these functions.&lt;/p&gt;

&lt;h1&gt;
  
  
  "Trimmed Text" = Table.TransformColumns(
&lt;/h1&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source,
{{"SKU", Text.Trim}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;)&lt;br&gt;
Cause 3: The Value Genuinely Doesn't Exist Yet&lt;br&gt;
Sometimes it's not a data quality bug — the fact table legitimately references something the dimension table doesn't have. A product was discontinued and removed from DimProduct, but historical FactSales rows still reference its old key. Or a new product started selling before the dimension table's daily refresh caught up.&lt;/p&gt;

&lt;p&gt;FactSales (2024-2026, includes discontinued products)&lt;br&gt;
DimProduct (current catalog only, discontinued products removed)&lt;/p&gt;

&lt;p&gt;ProductKey 1001 sold in 2024, but DimProduct no longer has it&lt;br&gt;
Fix: this is a referential integrity gap, not a formula bug. Either keep discontinued/historical members in the dimension table (with a flag like IsActive = FALSE instead of deleting the row), or add a placeholder row for exactly this case:&lt;/p&gt;

&lt;p&gt;DimProduct&lt;br&gt;
ProductKey | ProductName&lt;br&gt;
1001       | Trail Runner Tire&lt;br&gt;
1002       | Commuter Helmet&lt;br&gt;
-1         | Unknown Product      &amp;lt;- catches orphaned keys&lt;br&gt;
See Dimension Tables for why dimension tables are built to be the complete, authoritative list a fact table can always join against.&lt;/p&gt;

&lt;p&gt;Cause 4: A Default Value Was Never Set&lt;br&gt;
Independent of fixing the underlying data, LOOKUPVALUE() has an optional final argument specifically for this situation — a value to return instead of erroring when nothing matches.&lt;/p&gt;

&lt;p&gt;Product Category =&lt;br&gt;
LOOKUPVALUE(&lt;br&gt;
    DimProduct[Category],&lt;br&gt;
    DimProduct[ProductKey], FactSales[ProductKey],&lt;br&gt;
    "Unknown"&lt;br&gt;
)&lt;br&gt;
This doesn't fix why the key is missing, but it stops one bad row from breaking the entire calculation while the underlying cause gets investigated. See LOOKUPVALUE for the full syntax.&lt;/p&gt;

&lt;p&gt;Common Mistakes&lt;br&gt;
Adding a default value without investigating why. LOOKUPVALUE(..., "Unknown") makes the error go away, but if the missing keys represent a real data quality problem (like Cause 3), silently defaulting to "Unknown" can hide it indefinitely instead of fixing it.&lt;/p&gt;

&lt;p&gt;Assuming it's always a relationship problem. This specific error comes from LOOKUPVALUE() and similar functions evaluated directly — not from a standard modeled relationship, which handles unmatched keys differently (rows just don't appear, or appear under a blank member, rather than throwing this error). Don't go looking in Model view for a broken relationship when the actual cause is a DAX formula.&lt;/p&gt;

&lt;p&gt;Fixing the symptom on only one side. A type or whitespace mismatch usually needs fixing wherever the bad data originates, not just patching the lookup formula — otherwise the same mismatch reappears the next time new data loads.&lt;/p&gt;

&lt;p&gt;Checklist&lt;br&gt;
The specific missing keys have been identified (via a membership check), not just guessed at.&lt;br&gt;
Data types match exactly between the two columns being compared.&lt;br&gt;
Text keys are trimmed and case-normalized before being used as lookup keys.&lt;br&gt;
If the value is legitimately absent from the dimension table, that's addressed as a modeling decision (keep historical rows, or add a placeholder), not just papered over with a default.&lt;br&gt;
Originally published on PBIDocs — Power BI documentation covering DAX, Power Query, data modeling, and Microsoft Fabric.&lt;/p&gt;

</description>
      <category>data</category>
      <category>database</category>
      <category>software</category>
    </item>
  </channel>
</rss>
