CRM 2013 – Workflow error AccessCheckEx

I was investigating a bug on CRM 2013 , I got the exception below

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess Detail:
<OrganizationServiceFault xmlns:i=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts”&gt;
  <ErrorCode>-2147220891</ErrorCode>
  <ErrorDetails xmlns:d2p1=”http://schemas.datacontract.org/2004/07/System.Collections.Generic”&gt;
    <KeyValuePairOfstringanyType>
      <d2p1:key>OperationStatus</d2p1:key>
      <d2p1:value xmlns:d4p1=”http://www.w3.org/2001/XMLSchema&#8221; i:type=”d4p1:string”>0</d2p1:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <d2p1:key>SubErrorCode</d2p1:key>
      <d2p1:value xmlns:d4p1=”http://www.w3.org/2001/XMLSchema&#8221; i:type=”d4p1:string”>-2146233088</d2p1:value>
    </KeyValuePairOfstringanyType>
  </ErrorDetails>
  <Message>SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess </Message>
  <Timestamp>2015-06-23T10:02:24.458209Z</Timestamp>
  <InnerFault i:nil=”true” />
  <TraceText>

[Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.SyncWorkflowExecutionPlugin]
[0dac4467-fb18-e511-80ca-000c292122be: ]
Starting sync workflow ‘Task-Workflow’, Id: 04ac4467-fb18-e511-80ca-000c292122be
Entering ConditionStep1_step: If  Process contains data and is active
Entering SetStateStep4_step: Change record status to completed
Sync workflow ‘Task-Complete’ terminated with error ‘SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess ‘
</TraceText>
</OrganizationServiceFault>

Initial thoughts on the Error

I got this error and there were a few things I found interesting

This error was surprisingly informative

The error was thrown by a non code workflow but the cause of the error was thrown by a GUI workflow which was being triggered when a workflow tried to assign an activity.

I was impressed by the level of logging which was generated by a GUI/non code workflow.

I had never thought about it but this line

Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.SyncWorkflowExecutionPlugin

indicates CRM runs the GUI workflows using code, which must translate the actions into code. This is obvious but I hadn’t thought about it, until seeing the error.

You can use the callerid to find what user is doing the update and check what security roles the user has.

EntityTypeCode

In the error message you can see it mentions ObjectTypeCode

CRM 2011/2013 – Javascript to get the object type code of an entity

Each entity has an individual typecode, this CRM SDK page shows you the values of the default entities

Entity Type Code 4200 is ActivityPointer, which is interesting because the problem was being caused by an update to a task record.

Clues

AccessCheckEx failed – AccessCheckEx is something to do with security and access

In the error message you can see

AccessRights: WriteAccess

This is clearly telling us the user doesn’t have Write access, e.g. the user isn’t allow to update a certain

What was the cause

This bug was partly caused by the complexity of the CRM solution and the different customizations.

Solution complexity refer to not only the customizations which exist in the solution but the number of different customizations.  When a CRM solution has lots of different customizations e.g. workflows, plugins, business rules being triggered at the same time it makes it difficult to understand what is changing a value.

Below is what was happening

  1. A task was updated then saved
  2. This triggered a pre plugin on the task entity
  3. The plugin assigns the case record
  4. A plugin was triggered on assign of the case, which assigned all the open tasks to the new case owner
  5. The plugin(s) finished
  6. A workflow was triggered, which tried set the task to complete.

The error was thrown because the workflow was trying to update the task but the user only had privileges to update tasks they owned.

The reason this bug suddenly appeared was because the assign plugin was added and it wasn’t picked up in DEV testing because developers tested the code using users with System Admin privileges, which I have talked about before

The System Administrator role is a benefit and a curse to CRM developers

It’s tricky to test the effect of adding plugins

Having lots of different types of customizations adds to the complexity of your CRM solution, complex solutions are difficult to debug, understand and extend.

The Solution

Usually with bugs where the user doesn’t have the right security privilege the easy answer is to give the user role those security privileges.

For this bug it wasn’t the correct solution because the users only had access to tasks they owned and we didn’t want to suddenly give them permissions to update tasks they didn’t own.

The plugin code was running in a PRE plugin, so I couldn’t move the task completing code into this plugin.

The bug was becoming more tricky because I did want to keep the case assigning code in their but I didn’t want the assigning case plugin to run and assign the task to the new case owner because the task was about to completed.

My solution was to stop the assign plugin being triggered if was called by another plugin

Read how to do that in the blog below

CRM Plugins – Stopping infinite loops and understanding PluginExecutionContext.Depth

I then created a post task plugin to complete the task.  I didn’t need to do this but it seemed it would be easy to understand if all the changes were made by plugins.

There was an unsuccessful fix when I used impersonation to close the task as System Admin but the users didn’t like the tasks being closed by System Admin, they wanted the user who updated the task to complete the task.

You can read about Impersonation in plugins in the blog post below

CRM 2015 – Understanding impersonation in plugins and knowing when to use it

Advertisements