Troubleshooting Business Rules

Business Rules is composed of two components: a client side JavaScript and a server side workflow. You can use these queries to find out the details about this:

LinqPad – Query and result


FetchXml Builder – Query and result



One gotcha with the business rule is that its behavior will deviate, if a field that is required by the business rule is removed on the form. I will demonstrate this, with the business rule below.


This business rule sets the “Contracting Unit” to required, if Order Type is “Work Based”. Below are the screenshots of the form in two different scenarios:

With “Order Type” present on the form


Without “Order Type” present on the form

Without Order Type.png

As you can see, “Contracting Unit” is set to required, only if the “Order Type” field is present on the form, even if the value of “Order Type” is “Work based”. At present, there seems to no check in the form customisation area to prevent a field from being removed, if is required by a business rule. This is how the “Contracting Unit is required” business rule, gets translated into JavaScript.


When you debug this using Chrome Dev Tools, you can easily see why the “Contracting Unit” field is not being set to required.


To assist developers who are troubleshooting why a business rule is not working, I have developed this simple script to run in the DevTools console, that lists the fields that are required by the Business Rules, but are not present in the form. This has to be run in the context of ClientApiWrapper IFrame.

let formAttribs = Xrm.Page.getAttribute().map(a=>a.getName()); Object.keys(Mscrm.BusinessRulesScript.AttributesOnChangeHandlers).filter(x=>!formAttribs.includes(x))

Here is a sample output of this script.


It is saying that “Order Type” should be present in the form, as it is required by a Business Rule that is running on the form. It uses an unsupported internal method to identify this information, and so I recommend that it be used in devtools console only.

Further Reading:

Understanding Process Triggers and Business Rule internals

Bug: Branched Business Process Flow

Branched Business Process Flow was introduced in CRM 2015. I encountered a bug in BPF today, which took a day and a half to figure out. I am posting the scenario so that it will be beneficial for others who experience the same error. The bug is this:

When a lead is qualified an exception is thrown when:

  1. BPF has branches AND
  2. BPF has condition stages AND
  3. Some condition stages have only one output i.e only Yes or No
  4. Data in the form could lead to a condition block that will result in a dead end

This is the BPF, I created to test this bug.

Test BPF.png

As you can see I have a condition called “Existing account is not null”, and a stage if is true, not no stage if it is false. With this BPF an exception is thrown when the lead is qualified and Existing account is null. Below is the full error in Dynamics 365 Online.


<s:Envelope xmlns:s="">
			<faultstring xml:lang="en-US">An unexpected error occurred.</faultstring>
				<OrganizationServiceFault xmlns="" xmlns:i="">
					<ErrorDetails xmlns:a=""/>
					<Message>An unexpected error occurred.</Message>
					<ExceptionSource i:nil="true"/>
						<ErrorDetails xmlns:a=""/>
						<Message>System.ArgumentNullException: Value cannot be null.
Parameter name: g</Message>
						<ExceptionSource i:nil="true"/>
						<InnerFault i:nil="true"/>
						<OriginalException i:nil="true"/>
						<TraceText i:nil="true"/>
					<OriginalException i:nil="true"/>
					<TraceText i:nil="true"/>

This is the exception detail in CRM 2015.

<s:Envelope xmlns:s="">
			<faultstring xml:lang="en-AU">An unexpected error occurred.</faultstring>
				<OrganizationServiceFault xmlns="" xmlns:i="">
					<ErrorDetails xmlns:a="">
							<a:value i:type="b:string" xmlns:b="">   at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action)
   at Microsoft.Crm.Extensibility.Pipeline.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.MessageProcessor.&lt;&gt;c__DisplayClass1.&lt;RunStage&gt;b__0()
   at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action)
   at Microsoft.Crm.Extensibility.MessageProcessor.RunStage(PipelineExecutionContext context, Int32 pipelineStage)
   at Microsoft.Crm.Extensibility.MessageProcessor.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.InternalMessageDispatcher.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.ExternalMessageDispatcher.ExecuteInternal(IInProcessOrganizationServiceFactory serviceFactory, IPlatformMessageDispatcherFactory dispatcherFactory, String messageName, String requestName, Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, ParameterCollection fields, CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId, Guid transactionContextId, Int32 invocationSource, Nullable`1 requestId, Version endpointVersion)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequestRequestWithInstrumentation(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, OrganizationContext context, Boolean returnResponse, Boolean checkAdminMode, Object operation)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, OrganizationContext context, Boolean returnResponse, Boolean checkAdminMode)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, Boolean checkAdminMode)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.Execute(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, Boolean checkAdminMode)</a:value>
					<Message>An unexpected error occurred.</Message>
						<ErrorDetails xmlns:a="">
								<a:value i:type="b:string" xmlns:b="">   at System.Guid..ctor(String g)
   at Microsoft.Crm.ObjectModel.BusinessProcess.WorkflowConditionNextStageEvaluator.GetNextStage(StageStep stage)
   at Microsoft.Crm.ObjectModel.BusinessProcess.ActivePathEnumerator.MoveNext()
   at Microsoft.Crm.ObjectModel.BusinessProcess.ActivePathCalculator.Calculate(String targetEntityName)
   at Microsoft.Crm.Common.ObjectModel.NextProcessStageInformationFinder.CalculateGlobalStageAndTraversedInformation(String firstEntityName, String nextEntityName)
   at Microsoft.Crm.Common.ObjectModel.LeadService.QualifyLead(BusinessEntityMoniker leadId, Boolean createAccount, Boolean createContact, Boolean createOpportunity, BusinessEntityMoniker opportunityCurrencyId, BusinessEntityMoniker opportunityCustomerId, BusinessEntityMoniker sourceCampaignId, Int32 statusCode, ExecutionContext context)</a:value>
						<Message>System.ArgumentNullException: Value cannot be null.
Parameter name: g</Message>
						<InnerFault i:nil="true"/>
						<TraceText i:nil="true"/>
					<TraceText i:nil="true"/>

The root cause for this seems to beĀ GetNextStage. It seems the method can’t figure out what the next stage should be, when the BPF ends with a condition with only one branch. I haven’t tested other scenarios where this error could be triggered, but I was able to consistently reproduce the error on lead qualify.

Unrelated Note:

It seems business process has a client side caching mechanism. I had to clear cache every time after I made change to the BPF to test this issue.

Cherry picking Xrm.Internal

EDIT (09/02/17): This post is a result of my exploration into the Xrm.Internal namespace as other internal CRM code in general. It is not a recommendation to use this in a Production environment, as it is UNSUPPORTED. Since there are already ways to run SDK messages from JavaScript using many open source frameworks, I have decided not to post part 2 (how to do this using Xrm.Internal).

Word of warning: Code heavy post and nothing shown here is supported, as it uses internal methods. All these methods have been tested only in Dynamics 365 Online.

Xrm.Internal seems to be a goldmine for cool new functionalities, that one day will eventually make into the Client API. I will document some of the some methods that are useful.

Filter Partylist entity types – Hide unwanted

Scenario: You have opened a new email form. But, you don’t want users to choose contact or lead.

Method Definition: Xrm.Internal.filterLookupTypes([ATTRIBUTE],[ENTITY ARRAY], [FILTER TYPES])


Xrm.Internal.filterLookupTypes(Xrm.Page.getAttribute(“to”), [‘contact’,’lead’], true)





Filter Partylist entity types – Show wanted

This is the reverse of the previous scenario. You now want to show only contact and lead. In this case you can use this code.

Xrm.Internal.filterLookupTypes(Xrm.Page.getAttribute(“to”), [‘contact’,’lead’], false)

The order in which the entities appear matter. You can control the resolution order of the entities with this. The first entity on the array is the default selected entity type.

With parameter [‘contact’,’lead’]contact-first

With parameter [‘lead’,’contact’]


In both these cases, only the lead and contact entities are shown.


Get entity code from schema name

Method Definition: Xrm.Internal.getEntityCode([ENTITY SCHEMA NAME])




Get entity display name from schema name

Method Definition: Xrm.Internal.getEntityDisplayName([ENTITY SCHEMA NAME])




Get entity schema name from objecttypecode

Method Definition: Xrm.Internal.getEntityName([ENTITY OBJECT TYPE CODE])




Get state code name from integer value

Method Definition: Xrm.Internal.getStateFromNumber([ENTITY SCHEMA NAME],[STATECODES ARRAY])

getStateFromNumber returns a promise, not a simple value.




Get all features enabled for the current instance

One thing that caught my eye in the feature named “ServeStaticResourcesFromAzureCDN”. I know that learning path assets can be served from Azure CDN. Could this be opened up for other webresources in the future or is this strictly learning path only? I am not sure. Could “ODataV4UI” be Swagger UI or some sort of API Playground? Intriguing.

console.table(Object.keys(Mscrm.FeatureNames).filter(x=>!x.startsWith(‘_’)).map(x=> ({Feature: x, Enabled: Xrm.Internal.isFeatureEnabled(Mscrm.FeatureNames[x])})))





Business Solutions MVP – 2017

I was pleasantly surprised to see a MVP award notification email, when I woke up today morning.

MVP Email.png

I usually share stuff on Twitter pretty quickly, but I haven’t done so with this announcement, as I wanted to credit all the people who have not only helped me, but the whole CRM community with their insightful posts and awesome tools.

As a developer I really look up to these people, who have made some significant open source contributions and continue to:

  • XrmToolBox team (Alexey Shytikov, Daryl LaBar, Jonas Rapp, Tanguy Touzard)
  • Scott Durow
  • Jason Lattimer
  • Guido Preite
  • Yaniv Arditi
  • Lucas Alexander

The MVP program has also been updated. These are the key changes:

  1. New MVPs will be awarded every month (It was quarterly earlier)
  2. All renewals will happen on July

I think these changes are great, as this means more people will be able to come into the program quicker.


Bug: Notes creation in custom entity

There currently seems to be an issue in Dynamics 365 Online, where you can see notes in area in the custom entity, but cannot create new notes. I could reproduce this issue in this version -> Version 1612 ( (DB

This is how the notes area looks in a custom entity. There is no header area to create new notes.


Compare this with the contact entity.


As you can see, there is a textarea to create new notes, which seems to be missing in the custom entity. I looked into this using DevTools, and it appears to be display issue, as the DOM elements for creating the notes are still there. I quickly wrote this bookmarklet to temporarily show the create new notes text area in the form.


(function () {
	let contentPanels = Array.from(document.querySelectorAll('iframe')).filter(function (d) {
			return !== 'hidden'
	if (contentPanels && contentPanels.length > 0) {
		let activityWall = contentPanels[0].contentDocument.querySelector('#notesWall div.header');
		if(activityWall && === 'none'){ = ''
	} else {
		alert('Entity form not detected');


javascript:(function(){let contentPanels=Array.from(document.querySelectorAll('iframe')).filter(function(d){return!=='hidden'});if(contentPanels&&contentPanels.length>0){let activityWall=contentPanels[0].contentDocument.querySelector('#notesWall div.header');if(activityWall&&'none'){''}}else{alert('Entity form not detected');}})();void 0;

This is how the custom form will look, after you run the bookmarklet.


I am not sure what sets the “display” property to none. When the DOM element is initially created, it is created without the “display” property set and then some event handler appears to be modifying this. I set a DOM breakpoint on “Attributes modifications”, but the breakpoint is not retained when I refresh the page, and hence I am unable to catch the “display: none” being set on “#notesWall div.header”. I spent some time to investigate this from the pretty-printed source, but could not figure it out.

Executing large FetchXML with WebAPI

You can easily execute fetchxml in WebAPI using the “fetchXml” query parameter. But this “GET” method won’t work, if the fetchxml is too big. In this case, you have to use the “POST” method to execute the fetchxml.

Sample Request Header:

Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
Content-Type: multipart/mixed;boundary=batch_contactfetch

Sample Request Body:

Content-Type: application/http
Content-Transfer-Encoding: binary

GET https://[CRM URL]/api/data/v8.2/contacts?fetchXml=<fetch count="10" ><entity name="contact" ><attribute name="fullname" /></entity></fetch> HTTP/1.1
Content-Type: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0


Sample Code:

var req = new XMLHttpRequest();"POST", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/$batch", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_contactfetch");
req.onreadystatechange = function() {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 200) {
            var response = JSON.parse(this.response.substring(this.response.indexOf('{'),this.response.lastIndexOf('}')+1));
        } else {

var body = '--batch_contactfetch\n'
body += 'Content-Type: application/http\n'
body += 'Content-Transfer-Encoding: binary\n'
body += '\n'
body += 'GET ' + Xrm.Page.context.getClientUrl()+'/api/data/v8.2/contacts?fetchXml=<fetch count="10" ><entity name="contact" ><attribute name="fullname" /></entity></fetch> HTTP/1.1\n'
body += 'Content-Type: application/json\n'
body += 'OData-Version: 4.0\n'
body += 'OData-MaxVersion: 4.0\n'
body += '\n'
body += '--batch_contactfetch--'


Request Screenshot

Fetch Post Request.png

Response Screenshot


Gotcha: DateTimeKind and FetchXml

I was going through the FetchXML schema and found these two interesting attributes. The first one is “utc-offset” on the “fetch” node.


The other one is “usertimezone” on the “attribute” node.


Both these attributes give an impression, that it is possible to return datetime attributes in a different timezone instead of UTC, but in reality they don’t seem to do anything.

The only way to return datetime in the user’s local timezone, is by using the deprecated ExecuteFetchRequest. I will demonstrate this with XrmToolBox. This is my simple fetch query.


Below is the raw fetch result


Below is the table grid result


I execute the FetchXML using the FetchXML Builder tool. As you can see, the datetime values are different. This is because when you use “RetrieveMultiple” to execute the fetch query, the datetime returned is always UTC and has to be converted to the local timezone. ExecuteFetchRequest is now deprecated and RetrieveMultiple is the recommended way to execute fetchxml. These two points really puzzle me:

  1. Why user-timezone and utc-offset don’t seem to do anything. Are they internally used?
  2. Why MS decided to change the datetime behaviour

So, this is a good point to remember when you are executing fetchxml using “FetchXML Tester” or have set the Result view to Raw fetch result in “FetchXML Builder” or using a mixture of ExecuteFetchRequest and RetrieveMultiple in your code.


  1. ExecuteFetchRequest class
  2. XrmToolBox Issue #326