Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now! Learn more
I'm using the AdventureWorks2025 DB in a locally installed SQL Server instance. Original M code is below:
let
Source = Sql.Database("localhost\SQLEXPRESS", "AdventureWorks2025", [Query="select * from AdventureWorks2025.Production.ProductCategory#(lf);"])
in
Source
Tabular Editor 2 (which I'm launching from PBI desktop External Tools), I ran the following C# script to create a TSV file containing the table names in the Object column and the M code in the Expression column.
//Tabular Editor C# Script to Export PBI Tables and M Code
var tsv = ExportProperties(Model.AllPartitions, "Expression");
SaveFile("C:/Users/.../Export properties.tsv", tsv); //change ellipsis to specify file path
I then modified the TSV file with the following steps:
I then ran the following C# script UpdateMCodeFromTSV.cs to update the M code using the modified TSV file.
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
// Update the file path below to point to your TSV file
var filePath = @"C:\users\...\Export properties.tsv"; // <-- Change this path
if (!File.Exists(filePath))
{
Error(string.Format("File not found: {0}", filePath));
return;
}
// Read all lines from TSV
var lines = File.ReadAllLines(filePath);
if (lines.Length < 2)
{
Error("TSV file has no data rows.");
return;
}
// Parse Object and Expression columns from each line, skipping header
var mappings = new Dictionary<string, string>();
for (int i = 1; i < lines.Length; i++)
{
var parts = lines[i].Split('\t'); // ✅ Correct usage
if (parts.Length >= 2 && !string.IsNullOrWhiteSpace(parts[0]))
{
var objectName = parts[0].Trim();
var expression = parts[1]; // Keep full M code
mappings[objectName] = expression;
}
}
// Counters for summary
int totalProcessed = 0;
int successCount = 0;
int failureCount = 0;
foreach (var kvp in mappings)
{
totalProcessed++;
var objectName = kvp.Key;
var newExpression = kvp.Value;
Info(string.Format("Processing table: {0}", objectName));
var table = Model.Tables[objectName]
?? Model.Tables.FindByName(objectName)
?? Model.Tables.FirstOrDefault(t => t.Name.Equals(objectName, StringComparison.OrdinalIgnoreCase));
if (table == null)
{
Error(string.Format("Table '{0}' not found.", objectName));
failureCount++;
continue;
}
if (table.Partitions.Count == 0)
{
Error(string.Format("Table '{0}' has no partitions.", objectName));
failureCount++;
continue;
}
// Update M code in first partition
table.Partitions[0].Expression = newExpression;
Info(string.Format("Successfully updated M code for '{0}'.", objectName));
successCount++;
}
// Summary log
Info(string.Format("Summary: Processed {0} tables. Successes: {1}, Failures: {2}", totalProcessed, successCount, failureCount));
The C# script runs and updates the M code, but when I try to save the changes to the connected database, I get the following error message:
Does anyone know what I can do to get the changes to save to the database? I assume it has to do with the contents of the Expression column in the TSV file, but I'm not clear where it's expecting to see a comma (or if that's even what the error message actually means). This would be a huge help if I could get it to work for a much larger model that I'm trying to migrate to a new environment (the new environment uses a different variant of SQL, so it's more than just updating the database reference). Or is this a futile effort and I just need to migrate the model one table at a time in Power Query with manual code updates?
Thanks in advance for any insights!
Solved! Go to Solution.
Hi arc_gts,
Thank you for contacting the Microsoft Fabric Community Forum.
Based on my understanding, the issue is unlikely to be caused by Tabular Editor, C# scripts, or SQL connectivity. The save failure occurs because invalid Power Query (M) syntax is introduced during the TSV export/edit/import process, and Power BI validates M code only at save/deploy time using the Mashup engine. Specifically, manually replacing line breaks or tabs with #(lf) / #(tab), embedding multi-line SQL inside Query="...", or introducing encoding/escaping changes while editing the TSV can produce invalid serialized M code and trigger the “Microsoft.Data.Mashup.Preview;Token identifier expected” error.
The safest approach is to avoid embedding raw SQL text and instead rebuild the M expression using native Power Query navigation, for example, Sql.Database followed by schema or table navigation. This eliminates string escaping issues and is fully validated and supported by the Mashup engine:
let
Source = Sql.Database("localhost\SQLEXPRESS", "AdventureWorks2025"),
Product = Source{[Schema="Production", Item="Product"]}[Data]
in
Product
If embedding SQL text is unavoidable, ensure it remains single line, avoid #(lf) / #(tab) inside strings, preserve actual line breaks in the M script, and validate each updated query first in Power BI Desktop via Transform data → Advanced Editor before applying bulk changes. Once the M syntax is valid there, saving from Tabular Editor should succeed.
Please refer to the links below for further information:
Power Query M language specification - PowerQuery M | Microsoft Learn
Sql.Database - PowerQuery M | Microsoft Learn
External Tools in Power BI Desktop - Power BI | Microsoft Learn
Tabular modeling overview - Analysis Services | Microsoft Learn
We hope the above guidance helps resolve the issue. If you have any further queries, please feel free to contact the Microsoft Fabric community.
Thank you.
Hi arc_gts,
We would like to follow up and see whether the details we shared have resolved your problem. If you need any more assistance, please feel free to connect with the Microsoft Fabric community.
Thank you.
Hi arc_gts,
Thank you for contacting the Microsoft Fabric Community Forum.
Based on my understanding, the issue is unlikely to be caused by Tabular Editor, C# scripts, or SQL connectivity. The save failure occurs because invalid Power Query (M) syntax is introduced during the TSV export/edit/import process, and Power BI validates M code only at save/deploy time using the Mashup engine. Specifically, manually replacing line breaks or tabs with #(lf) / #(tab), embedding multi-line SQL inside Query="...", or introducing encoding/escaping changes while editing the TSV can produce invalid serialized M code and trigger the “Microsoft.Data.Mashup.Preview;Token identifier expected” error.
The safest approach is to avoid embedding raw SQL text and instead rebuild the M expression using native Power Query navigation, for example, Sql.Database followed by schema or table navigation. This eliminates string escaping issues and is fully validated and supported by the Mashup engine:
let
Source = Sql.Database("localhost\SQLEXPRESS", "AdventureWorks2025"),
Product = Source{[Schema="Production", Item="Product"]}[Data]
in
Product
If embedding SQL text is unavoidable, ensure it remains single line, avoid #(lf) / #(tab) inside strings, preserve actual line breaks in the M script, and validate each updated query first in Power BI Desktop via Transform data → Advanced Editor before applying bulk changes. Once the M syntax is valid there, saving from Tabular Editor should succeed.
Please refer to the links below for further information:
Power Query M language specification - PowerQuery M | Microsoft Learn
Sql.Database - PowerQuery M | Microsoft Learn
External Tools in Power BI Desktop - Power BI | Microsoft Learn
Tabular modeling overview - Analysis Services | Microsoft Learn
We hope the above guidance helps resolve the issue. If you have any further queries, please feel free to contact the Microsoft Fabric community.
Thank you.
Thanks, this is very helpful. While it's not the answer I was hoping for, now I know that it won't be productive to pursue this method of updating my semantic model any further.
The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now!
| User | Count |
|---|---|
| 19 | |
| 10 | |
| 9 | |
| 8 | |
| 7 |