The ability to merge records is a powerful one in keeping control of your data quality within PowerApps / D365. It can also be deceptively complex. As we’ve been living & breathing this area of the platform for several years during the development of data8 duplicare, we’ve seen a lot of unexpected things show up when merging particular records. To help understand why you might get an error when merging, I’ve tried to “deconstruct” the merge process below.
Helper Tool: If you’re here because you’re getting permission errors when merging records, check out my free Merge Permissions tool for XrmToolBox – automatically add all the permissions you need to a security role.
Basic Validation
There’s a whole bunch of conditions that must be met before two records can be merged. If these aren’t met, you should get an error message back pretty quickly. Most of these errors are quite self-explanatory, but there are some that took a little more digging to get to the bottom of.
- You can’t merge a record with itself. Kind of goes without saying, but we had to check! If you try and merge a record with itself you’ll get the error
Merge cannot be performed on master and sub-entities that are identical.
- You can only merge accounts, contacts, leads and cases. Try to merge anything else and you’ll get the error
This type: {name} is not supported with merge operation
- Both the master and subordinate records must be active. If you try to merge an inactive record you’ll get one of the following messages:
master entity:{name}-{id} is deactive
sub-entity:{name}-{id} is deactive
- Security checks. You need several different security privileges to be able to merge:
Privilege | Required On |
---|---|
Read | Master Record |
Write | Master & Subordinate Records |
Share | Master Record |
Append To | Master Record |
Merge | Global |
If you’re missing any of these you’ll get the rather ambiguous message “Merge is not allowed: caller does not have the privilege or access”. You can use a tool use as the XrmToolBox Access Checker plugin to find out exactly which privilege you are missing. If you’re on-prem then you can take a look at the server trace logs to get more details.
Advanced Validation
Now we’ve got the basic sorted, there are some more detailed validation checks that the system will run depending on the type of records being merged:
- You can’t merge cases with different parents. If you try you’ll get the error “Child cases having different parent case can not be merged.”
- You can’t merge accounts or contacts with different parents unless you specify the
PerformParentingChecks
parameter as false. Otherwise you’ll get one of the following messages:Merge warning: sub-entity might lose parenting
(if the subordinate record has a parent but the master doesn’t)Merge warning: sub-entity will be differently parented.
(if the master and subordinate records both have different parents)
- You can’t merge cases that have more than 100 child cases between them. There is a system-defined limit of 100 child cases per parent case, so if you try to merge two cases that each have 60 child cases, that would result in the final merged case having 120 children, which isn’t allowed. This triggers the error message
A Parent Case cannot have more than 100 child cases. Contact your administrator for more details
- You can’t merge accounts or contacts that have an active quote. Specifically, the subordinate record can’t have an active quote, but the master record can. If you try to merge two records where the subordinate has an active quote you’ll get the error
Merge cannot be performed on sub-entity that has active quote.
- You can’t merge records if that would create a loop in a hierarchy. For example, if you have a hierarchy of accounts A <- B <- C, and try to merge A and C. That could result in the parent of A being B (copying the parent from C), and the parent of B being A. If you end up in this situation you’ll get one of the following errors:
Merge could create cyclical parenting.
(account)-
Loop exists in the contacts hierarchy.
(contact) Creating this parental association would create a loop in Contacts hierarchy.
(contact)
Move Related Records
Now it’s done all the up-front checks, it’s time to move onto the interesting bit – moving the records that were related to the subordinate record over to the master.
At this point the system goes through all 1:N and N:N relationships with a Merge
cascade type of Cascade All
(note that you can’t change this cascade type – it will typically be Cascade All
except for a few system-managed relationships).
All records related to the subordinate record through one of these relationships will be updated to refer to the master record. This requires Append
and Write
privileges on the related record. If you don’t have those privileges you’ll get an error like SecLib::AccessCheckEx2 failed. Entity Name:activitypointer,OwnershipTypeMask:UserOwned, ObjectId: 98dbe456-43b3-e711-80e6-3863bb35af60, OwnerId:843ef80e-6a51-e511-9759-f0921c100524, OwnerIdType:8, OwnerData: roleCount=2, privilegeCount=2993, accessMode=0 and CallingUser:100781f5-c4d6-e311-aec5-d89d6764507c, CallerBusinessId:0c92636a-d920-e511-b427-d89d67632c70 PrincipalData: roleCount=5, privilegeCount=1141, accessMode=0. ObjectTypeCode:4200, ObjectBusinessUnitId:0c92636a-d920-e511-b427-d89d67632c70, AccessRights: WriteAccess. Computed rightsToCheck=WriteAccess, grantedRights=8, hsmGrantedRights=None, grantedRightsWithHsm=8,
The highlighted parts help you identify the type of record and the ID of the individual record that the user is missing permissions on, and the permission that is missing.
It will also update any activities that have the subordinate record as a party (sender, to, organizer etc.) to use the master record instead, even though the Activity Party relationships have a Merge
cascade type of Cascade None
.
Each of these updates can in turn trigger workflows or plugins that can have any number of other side effects, so it’s quite common to see other errors here. It can be difficult to debug these – the simplest way beyond trial and error is to get access to the trace logs which should tell you what entity type and record ID is triggering the error.
If you find that merging is taking a long time, it’s normally this step that’s the problem. Check your foreign key indexes, synchronous plugins and workflows.
Sharing
The next non-obvious part of the process is that any related records that have been moved from the subordinate to the master will now be shared with the owner of the master record. For example, if you merge two accounts, the contacts that were associated with the subordinate account will be shared with the owner of the master account. This tends to make things “just work” as most users would probably expect, but may break your security model. If you want to disable this behaviour you can do so by changing the GrantFullAccessForMergeToMasterOwner
organisation setting to False.
Similarly, the master record will be shared with the owner of the subordinate record. To turn this off, use the GrantSharedAccessForMergeToSubordinateOwner
organisation setting.
Finally, reparenting rules are applied. Any 1:N relationships with a Reparent
cascade rule will be processed to share the related records with the owner of the master record.
Updating the Master
Any updates to the master record are applied, e.g. if you want to take data from the subordinate record that is missing or incorrect on the master.
In the merging UI in the web application you can only select values to update that are in the same field on each record, i.e. use Email Address 1 from either the master or subordinate. Using the SDK however, there’s nothing to stop you taking values from elsewhere, or even just making up entirely new values that don’t exist in either record, by populating the UpdateContent
parameter of the MergeRequest
.
Deactivating the Subordinate
The subordinate record is linked to master record and deactivated. The state code and status code of the subordinate will be set as follows:
Entity Type | State Code | Status Code |
---|---|---|
Account | 1 | Default |
Contact | 1 | Default |
Lead | 2 | Default |
Case | 2 | 2000 |
This can trigger an error when restricted state transitions have been set up for cases: “The merge couldn’t be performed. One or more of the selected cases couldn’t be cancelled because of the status transition rules that are defined for cases.”
The default status code for a state code can be selected within the attribute customization screen, currently this can only be done through the classic UI:
Version 9 Changes
Merging has stayed essentially unchanged since at least version 4, but version 9 introduced a few new standard plugins that attach to the Merge message and can trigger some different error messages.
In the Move Related Records section above, we saw the rather unhelpful error message that was returned when the user doesn’t have permissions to move one of the related records from the subordinate to the master record. Version 9 introduces a new plugin Microsoft.Dynamics.Sales.Plugins.PreOperationAccountMerge
, and while it’s not immediately clear what this plugin does, it does generate a more helpful version of the same error:
Principal user (Id=
100781f5-c4d6-e311-aec5-d89d6764507c , type=8) is missing prvReadCustomerOpportunityRole privilege (Id=db84e2ea-44fe-44ff-b01c-bd1b3d3d07ae)
Rather less helpfully, it also introduces plugins for the Microsoft Dynamics for Marketing product. One of these, Microsoft.Dynamics.Marketing.Plugins.PreDisassociateEntitiesPlugin
, will commonly trigger errors when the subordinate record being merged is a member of a marketing list. If you receive an error such as:
Disassociation cannot be performed between an entity of type list and an entity of type account.; [Microsoft.Dynamics.Marketing.Plugins: Microsoft.Dynamics.Marketing.Plugins.PreDisassociateEntitiesPlugin]
then you have hit the bug in this plugin. There isn’t anything wrong with your process, code or data, but to work around the bug you’ll need to first remove the subordinate record from any marketing lists then merge the records again. If you want to preserve the marketing list membership, you’ll need to manually add the master record to the same marketing lists as the subordinate record was part of.
Thank you for this really good explanation. It helped me a lot by identifiying an access issue.
Have you come across a case where the system gives you permission to merge, but the Merge Records screen shows random fields that aren’t actually in use on your customised Contact form? We’re seeing this happening where fields are correct and as expected for administrators but incorrect for users.
No, I haven’t come across that before. Is it possible that the user seeing the other fields is using a different Contact form than the one you’re expecting?
We see if some occasions, that the inactive account after the merge, still has some invoices. What could this be?
Master account has different owner then inactive account. And invoice on inactive account has a different owner then both accounts.
That’s not something I’ve seen before. Were the invoices linked to the old account before the merge, or have they been added after?
Hi Mark, This is a very useful article which helped me to setup a security role for merging with all required permissions. My question is: do you know if this is still valid in the latest version of DYN365 CE 9.2.23075.00198 online
Thanks
I haven’t re-checked this recently but as far as I know this is still valid. If you find anything else is missing please let me know!
Hello good information. We are getting an error cannot update closed or cancelled activity when merging two accounts.
I am system administrator
Most likely there’s a plugin or real-time workflow running which is triggering this – if you get the full error log it should include some more details to point you in the right direction
Hi Mark, thanks for this article. We’re seeing issues now with the new Real-Time Marketing tool in Customer Insights – Journeys. None of the contact’s Insights data is coming over to the Master records, and if the subordinate record was in a journey, the Master does not replace the contact in that journey… Would you have any tips here? Or has Microsoft added any functionality to the Merge to work with Real-Time marketing?
This is currently a known limitation of Customer Insights Journeys, hopefully this might get some improvement in a future update!
Hi Mark,
First of all – great stuff – like SQL4CDS, still one of my favourites.
I have a short question concerning the advanced validation point 3. What do you mean with child cases? Does this include all activities and also tracked mails? I wanted to merge 2 contacts and ran into an error – unfortunately a general one with no details. I’ve seen that one of the contacts has many activities (around 188) including tracked mails. The activities are a mix of regarded and related records – if this makes a difference.
Is there a limit of 100 – so that the merge doesn’t work?
Thanks and best regards
Carsten
Ok, reading it for the 10th time, I think this just belongs to cases doesn’t it? 🙂
If it’s for contacts or accounts you mentioned it exactly.
Correct – merging any record type will always move related activities including tracked emails. Over 100 related activities shouldn’t normally be a problem, though it may take a little while to run.