Your audit trail disappears between SharePoint and OneLake
A data engineer mirrors a SharePoint list into Microsoft Fabric. The list tracks project approvals — each row has a status, a deadline, and a "Reviewed By" person column that the compliance team needs for audit purposes. The mirror completes without errors. The row counts match. But when the compliance analyst opens the SQL analytics endpoint, the Reviewed By column is either missing entirely or populated with nulls.
No warning surfaced during setup. No error appeared in the monitoring hub. The mirroring status showed healthy replication. The data loss only became visible when someone queried the table and noticed the gap — sometimes days after the mirror was configured.
This is not a bug in the traditional sense. It is a design constraint. SharePoint stores Person/Group fields as nested JSON objects containing a display name, email address, claims-based identity string, and additional metadata. Fabric's mirroring and copy activities expect flat, scalar column types: strings, integers, dates, decimals. When the replication engine encounters a nested object it cannot map to a scalar type, it skips the column rather than failing the entire job.
The silence is the problem. A hard failure would prompt investigation. A quiet omission lets bad data propagate downstream into Power BI reports, compliance exports, and operational dashboards — all showing incomplete records that look complete because every other column came through fine.
SharePoint stores people as nested objects, not strings
Understanding why these columns vanish requires looking at how SharePoint Online actually stores person-type data. When you create a Person or Group column in a SharePoint list, the underlying REST API (/_api/web/lists/getbytitle('YourList')/items) returns that field not as a simple string but as an object with multiple properties:
{
"ReviewedById": 42,
"ReviewedBy": {
"Title": "Jane Park",
"EMail": "jane.park@contoso.com",
"LoginName": "i:0#.f|membership|jane.park@contoso.com"
}
}The Title, EMail, and LoginName properties are each strings, but they live inside a nested structure. SharePoint also exposes a companion integer column (ReviewedById) that holds the internal user ID — but this ID is site-collection-scoped and meaningless outside SharePoint.
Fabric's SharePoint Online List connector, available through Dataflow Gen2 and Pipeline copy activities, maps columns to a flat tabular schema. When it encounters a nested object, the mapping fails silently. The connector does not attempt to auto-flatten the structure or pick a default sub-property like Title. It simply omits the column from the output.
This behavior applies to every Person/Group column in the list: Created By, Modified By, and any custom people-picker fields. It also affects other complex column types like Managed Metadata (taxonomy) fields and multi-value Lookup columns, which share the same nested-object storage pattern. If your SharePoint list uses any of these, expect the same silent omission.
Fix it at the source: calculated columns in SharePoint
The most durable fix happens in SharePoint itself. Before data ever leaves the list, you create additional columns that extract the scalar values you need from the nested Person/Group fields.
SharePoint supports calculated columns, but they cannot reference Person/Group fields directly — a long-standing platform limitation. Instead, use one of two approaches:
Approach 1: Formula-driven text columns via Power Automate. Create a plain text column called ReviewedByName. Build a Power Automate flow triggered on item creation and modification that copies the display name from the Person field into the text column. The flow expression is straightforward: triggerOutputs()?['body/ReviewedBy/DisplayName']. This text column replicates cleanly into Fabric because it is a simple string.
Approach 2: SharePoint column formatting with JSON. You can also use SharePoint's JSON column formatting to display person data differently, but this only affects rendering — it does not change the underlying data type. For replication purposes, the Power Automate approach is the one that works.
The tradeoff is maintenance overhead. Every Person/Group column you need in Fabric requires a companion text column and a flow to keep it synchronized. For lists with three or four person fields, that means three or four additional columns and corresponding flow logic. If someone adds a new person column to the list six months from now, the mirror will silently drop it unless the companion column and flow are also created.
Despite this overhead, the source-side fix is preferable when the SharePoint list is under your team's control. The data arrives in Fabric already clean, and downstream transformations do not need to account for missing columns.
Fix it in Fabric: flatten nested structures post-load
When you cannot modify the SharePoint list — perhaps it is owned by another team, or governed by a change management process — you flatten the nested data inside Fabric instead.
Dataflow Gen2 is the lowest-friction option. Create a dataflow that connects to the SharePoint Online List source. In the Power Query editor, select the Person/Group column and use the expand-column operation to extract Title, EMail, or whichever sub-properties you need. The expanded columns become standard text fields in the output table. Schedule the dataflow on the cadence your use case requires.
Fabric Notebooks with PySpark give you more control. Use the SharePoint REST API directly to pull list items into a DataFrame, then parse the nested JSON:
from pyspark.sql.functions import col, get_json_object
df = spark.read.json("/lakehouse/default/Files/sharepoint_raw/approvals.json")
df_flat = df.select(
col("Title"),
col("Status"),
get_json_object(col("ReviewedBy"), "$.Title").alias("ReviewedByName"),
get_json_object(col("ReviewedBy"), "$.EMail").alias("ReviewedByEmail")
)
df_flat.write.mode("overwrite").format("delta").saveAsTable("approvals_clean")This approach works well when you are already using notebooks for other transformation logic. It also lets you handle edge cases — like multi-value person fields where the JSON contains an array of user objects rather than a single object.
Fabric Pipelines with a Copy activity can land the raw data into a Lakehouse Files section as JSON, which you then process with a subsequent notebook or dataflow step. This two-stage pattern (land raw, then transform) gives you a recoverable intermediate layer if the transformation logic needs to change later.
The Fabric-side fix avoids touching the source system but introduces a transformation dependency. If SharePoint's API changes the nested structure — which has happened in minor ways during feature rollouts — your flattening logic breaks silently until someone notices the nulls again.
Mirroring is not yet available for SharePoint lists
A critical clarification: as of June 2026, SharePoint Online lists are not a supported source for Fabric's native mirroring feature. The supported mirroring sources are relational databases — Azure SQL, Cosmos DB, Snowflake, Oracle, PostgreSQL, and others — plus metadata mirroring for Azure Databricks Unity Catalog.
When community discussions reference "SharePoint list mirroring," they typically mean replicating SharePoint data into Fabric using Data Factory connectors (Dataflow Gen2, Pipeline copy activities, or Copy jobs) on a schedule. This is ETL-based replication, not the continuous change-data-capture mechanism that Fabric mirroring provides for supported databases.
The distinction matters for two reasons. First, there is no near-real-time sync. Your SharePoint data in Fabric is only as fresh as your last scheduled pipeline run. If you schedule hourly refreshes and a list item changes at minute one, it will not appear in Fabric until the next run. Second, there is no automatic schema synchronization. If someone adds a column to the SharePoint list, your pipeline does not pick it up automatically — you must update the dataflow or copy activity mapping.
This gap creates a monitoring blind spot. A pipeline that ran successfully an hour ago might be copying stale schema definitions, delivering data with silently missing columns. The pipeline status shows success because it copied all the columns it knew about. The new column simply does not exist in its mapping.
MetricSign detects this class of issue through its refresh_delayed signal — when the expected data freshness from a Fabric pipeline diverges from the actual state, it surfaces the gap before a stakeholder discovers stale or incomplete data in a downstream report.
Build a checklist before you replicate any SharePoint list
Every SharePoint-to-Fabric replication should start with a column audit. Before configuring your first dataflow or pipeline, export the list schema and classify each column by data type.
Pull the schema from the SharePoint REST API: GET /_api/web/lists/getbytitle('YourList')/fields?$filter=Hidden eq false. Inspect the TypeAsString property for each field. Flag any column where TypeAsString equals User, UserMulti, TaxonomyFieldType, TaxonomyFieldTypeMulti, or LookupMulti. These are your nested-object columns. They will not transfer cleanly without intervention.
For each flagged column, decide: source-side fix (companion text column plus Power Automate flow) or Fabric-side fix (expand in Dataflow Gen2 or parse in a notebook). Document the decision. When someone adds a new person column to the list months from now, this documentation tells the next engineer what pattern to follow.
Set up a row-count and column-count validation step in your pipeline. After each load, compare the column count in the destination table against the expected count from your schema audit. A mismatch means a column was added or dropped. This is a simple check — a single SQL query against INFORMATION_SCHEMA.COLUMNS — but it catches the silent omission problem that makes SharePoint replication unreliable.
Finally, test with real data before going to production. Create a test list with every column type SharePoint supports — text, number, date, person, managed metadata, multi-value lookup, hyperlink, image — and run your pipeline against it. Verify which columns appear in the destination and which do not. This ten-minute test saves hours of debugging when a report consumer asks why the "Approved By" column is blank.