I recently ran into a tricky issue while working on a custom ribbon button in Dynamics 365 Sales. The button triggered a JavaScript function that executed a bound custom action via Xrm.WebApi.execute()
. This action was tied to a synchronous plugin, which was designed to call two standard actions:
WinQuote
ConvertQuoteToSalesOrder
Everything looked fine on the surface — the Web API returned a 204 No Content
response, which typically means success.
But in reality?
Nothing happened. The quote remained active, and no sales order was created.
The Setup
- A ribbon button triggers JavaScript, which calls a bound custom action.
- The action invokes a synchronous plugin.
- The plugin runs
WinQuote
, followed byConvertQuoteToSalesOrder
.
The Problem
Despite getting a 204 response, no updates were made:
- The quote wasn't won.
- No sales order was generated.
- No error message was returned.
- Plugin trace logs showed no execution — it was as if nothing had run at all.
Fix #1: Input Parameter Type
The plugin originally checked for an Entity
in the Target
parameter. But with WebApi.execute()
and bound actions, the Target
is passed as an EntityReference
.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is EntityReference targetRef)
{
// Proceed with business logic
}
Once corrected, the plugin began executing as expected.
Fix #2: Return Output Parameters
To avoid silent 204s and get better error visibility, I updated the plugin to include output parameters in the action response:
context.OutputParameters["Success"] = false;
context.OutputParameters["ErrorMessage"] = "Quote is already closed.";
In the JavaScript:
Xrm.WebApi.execute(request).then(function(response) {
response.json().then(function(data) {
if (!data.Success) {
alert("Plugin Error: " + data.ErrorMessage);
}
});
});
This allowed meaningful errors to surface in the UI instead of vanishing silently.
Lessons Learned
A 204 response doesn't always mean success — it just means the action didn’t return content or throw a top-level error.
Plugins triggered by actions often receive EntityReference, not full Entity records.
Adding output parameters is a great way to pass status/error info back to the client.
Plugin trace logs are essential when you’re troubleshooting backend logic.
Final Thoughts
If you're using custom actions with plugins and you're not seeing the expected results, don’t stop at a 204. Dig deeper — check parameter types, log traces, and return custom responses. A few small changes helped me get everything working smoothly.
In a follow-up post, I’ll explain why I chose to use a combination of JavaScript, Custom Action, and Plugin instead of directly handling everything in JavaScript — and how this architecture sets us up to scale the solution using Power Automate for large-volume processing. Stay tuned!