Plugins recursion – how can you handle it?

By | December 29, 2017


What if you register a plugin step on update of some attribute, and, then, update the same attribute in the plugin again?


Dynamics can’t decide, for you, when is the right time to stop this endless loop, but it will detect the recursion, and, after a few repetitions, will stop it:


It will do the same in many different situations. It can be one plugin, or a chain of plugins, or a chain of workflows, or a mix of those. They can be synchronous or a-synchronous, they just have to be executing as a result of the same original operation. There are some finer settings (which you can’t easily change, especially in the online environments) which control when Dynamics will interfere, but, in the end, as soon as the number of those sequential plugins/workflows reach a certain limit within a pre-defined timeframe, you will get a similar error message.

There are a few optimizations/workarounds available to you:

– Always define specific triggering attributes for your steps. Don’t just leave “all attributes” there. That way, you will reduce the possibility of occasional recursion, but you won’t be able to completely avoid it

– You can use context.Depth property which is available in the plugin execution context. It will keep increasing for every new workflow/plugin in the “chain”. For every new “update”, Depth will start with 1. Then, if, inside the first plugin step you do something that start another plugin, that second plugin will have Depth=2 in the context. And it will keep increasing till it reaches the point where Dynamics will interrupt the process. Although, keep in mind that those have to be sequential events where one event is causing the other. If, for instance, there are two pre-operation steps on Update of the same entity, both responding to the update of the same attributes, “Depth” will be the same in those two steps(since, from the Depth perspective, they are “parallel”.. not sequential). This is why you will often see this condition in the plugins:

if (context.Depth > 1) return;

That works, but that introduces a hidden problem. Imagine that you have a plugin that’s doing something on update and that has that kind of condition. You have deployed the plugin, you have tested it by opening the entity in Dynamics, updating a field, and verifying that the plugin kicked in. It is depth 1, so it’s all good:


But what if we change it a little?


Now it’s, suddenly, Depth 2, and the plugin will not kick in when the update happens from a workflow/another plugin. Which you may or may not discover until such time when somebody has created a workflow, started to use it, and, then, somebody else pointed out that the data is not consistent anymore

– Do not make the beginner’s mistake

Never do this:

Entity entity = (Entity)context.InputParameters[“Target”];


Instead, always create a new in-memory entity, assign the id, and set only the attributes you want to update:

Entity entity = (Entity)context.InputParameters[“Target”];

Entity updatedEntity = new Entity(entity.LogicalName);

updatedEntity.Id = entity.Id;

updatedEntity[“attribute”] = value;


– Try not to call service.Update at all – in the pre-operation step, you can use Target to set the attributes. There is no need for a separate Update call, and, if there is no such call, there is no recursion at all:

Entity entity = (Entity)context.InputParameters[“Target”];

entity[“attribute”] = value;

Leave a Reply

Your email address will not be published. Required fields are marked *