The release pipeline imports the managed solution cleanly. No errors, no warnings. You open the target environment to verify the form change you made - and the form looks exactly like it did before the deploy.
The instinct is to suspect the deploy. Re-run it, re-export, compare zip contents. Everything checks out. The real cause, almost every time, is Dataverse's solution layering model: your managed solution update is being overridden by a higher-priority layer that nobody remembered was there.
The mental model
Dataverse stores each customizable component as a stack of layers. When the runtime renders a form or applies a business rule, it walks the stack top-to-bottom and takes the first layer that defines that property.
The layer order, highest priority first:
- Active (unmanaged) customizations - anything edited directly in the target environment without going through a solution
- Unmanaged solutions - containers of unmanaged components (rare in Prod, common in Dev)
- Managed solution layers, most recently imported first - your client's project solution, then dependencies, then Microsoft's built-in solutions
When you update a managed solution, you add (or modify) a layer near the top of the managed stack - but still below any unmanaged customization that exists for the same component. If someone added an unmanaged change at any point, it wins.
How components get accidental unmanaged layers
Three common causes:
- Someone edited directly in UAT or Prod. Configuration changes made through the maker portal or classic customization without a solution context are unmanaged. One afternoon of "quick fix" creates a layer that silently overrides every future managed deploy.
- A user with broad privileges imported an unmanaged solution to test something, and did not uninstall it.
- A managed solution was imported with OverwriteUnmanagedCustomizations=false in the pipeline. In some import modes this preserves existing unmanaged layers instead of overwriting them - which is sometimes the correct choice but is usually not what you want on a clean deploy.
Diagnosing the layer stack
Dataverse gives you two ways to inspect the active layer for a component.
UI path: Open the component in the maker portal (a table form, for instance). On the left navigation, look for "Solution Layers" or equivalent. It shows every layer that has defined this component, in priority order. The topmost layer is what users see.
API path (faster for scripting): Use the RetrieveEntityRibbon or the newer /api/data/v9.2/msdyn_solutioncomponentsummary virtual entity to list component layers programmatically.
We have a small PowerShell script that lists the top layer for every form in a target environment:
Anything with Managed: False in the TopLayer is an unmanaged override.
Three fixes
Fix 1: remove the unmanaged layer (most common case).
In the maker portal's Solution Layers view, the top unmanaged layer has a "Remove active customization" option. Using it removes the unmanaged customization for that specific component, letting the next layer down (your managed layer) become active.
Caveats:
- This applies per component. If the unmanaged change spans ten components, you remove ten times.
- If the unmanaged layer had a change the business actually wanted, you will remove that change too. Confirm before clicking.
Fix 2: merge the unmanaged change into your solution, then redeploy.
If the unmanaged change is legitimate (a real business fix applied out-of-process), the right fix is to pull it into your Dev environment, add it to the solution properly, and ship it through the pipeline. Then remove the unmanaged layer in UAT/Prod as in Fix 1.
This is the scenario where direct changes happen for good reasons during an incident. The cleanup afterwards is to merge back into source.
Fix 3: import with OverwriteUnmanagedCustomizations=true.
The PowerPlatformImportSolution pipeline task takes this flag. Setting it true tells Dataverse to remove any conflicting unmanaged customizations when the managed import runs.
We use this on Test (where there should never be intentional unmanaged changes) but not on UAT or Prod (where an unplanned overwrite could erase an in-flight hotfix).
The prevention we enforce
After two full-day debug sessions on layering issues, we now enforce four rules on every project:
- Service principal deploys only to UAT and Prod. Human accounts cannot import unmanaged solutions there.
- Customization is locked in UAT and Prod via security roles - no user has the privilege to edit forms, fields, or views directly.
- Any hotfix applied directly must be backfilled into source control within 48 hours, with an automated reminder if it has not been done.
- A pre-release layering scan runs the PowerShell check above and flags any unexpected unmanaged layers before the pipeline kicks off a deploy.
The layering model is not the bug. The bug is forgetting the layering model exists and making changes outside it. The four rules above keep the model predictable, and when something does slip through, the diagnostic script tells you exactly where to look.