Fixed –Lookup value plugintypeexportkey [Guid] is not resolvable – Solution Import error (Dynamics 365 / Dataverse)


Recently, we faced an interesting import failure while moving a solution containing a Custom API.

Solution “Temp Plugin Step Custom API Transfer” failed to import: Lookup value 8f3269b7-a24d-43e4-9319-0c5e7ddf2b53 is not resolvable.

A screen shot of a computer

AI-generated content may be incorrect.

This clearly pointed to a lookup resolution issue — the solution import process was trying to bind the Custom API to a Plugin Type (class), but couldn’t find the referenced plugin in the target environment.

Each Custom API will have its own folder inside the Solution.

A screenshot of a computer

AI-generated content may be incorrect.

Looking into the solution files (specifically the customapi.xml) of that particular Custom API, we found this section:

A screenshot of a computer
AI-generated content may be incorrect.

Notice the <plugintypeexportkey> tag. This is where the Custom API references the Plugin Type (the actual C# class implementing the logic).

A computer screen with text and arrows pointing to it

AI-generated content may be incorrect.

When a Plugin class is created in Dynamics 365, it gets assigned a unique Plugin Type Id (GUID).

In the source environment, the Custom API was tied to a plugin with ID 420c7261-7461-4b37-87f0-1afcec427a46. However, in the destination environment, which was another development environment, a different plugin class was already created for that custom api. So during solution import, Dataverse tried to match the GUID 420c7261… but couldn’t find it in the target environment. Hence, the lookup resolution failed, and the solution import was blocked.

To resolve this, we manually updated the GUID in the customapi.xml to match the Plugin Type Id of the destination environment. Below, we are getting the ID from the Plugin Registration tool. The other option to fix would have been to remove the Plugin reference from the source, export, and then import.

A screenshot of a computer

AI-generated content may be incorrect.

After making this change, we re-imported the solution, and it worked successfully.

Also check – https://technicalcoe.com/2024/07/04/troubleshooting-power-platform-solution-import-errors/

Hope it helps..

Advertisements

Using addNotification to Simulate Dynamic Tooltips (Dataverse / Dynamics 365)


When working with forms in Dynamics 365 / Power Apps model-driven apps, we often customize field labels based on context, using the setLabel method. At times, we would also like to change the tool tip to go with the changed label of the field. The tooltip is defined as a Description of the field.

Below is the Topic (subject) field of the lead.

A screenshot of a computer

AI-generated content may be incorrect.

However, we cannot set the tool tip (description) of the field dynamically in the form using the Client API. So, what do we do when the meaning of a field changes depending on another value on the form? That’s where addNotification comes in as a handy workaround.

Let us take a simple example to see how we can use it. On the Lead form, the Topic(subject) field means different things depending on the Lead Source. So here we will be changing the label of the Topic (subject) field, along with setting a different notification message.

For e.g., if Lead Source – Advertisement, we are changing the label to Campaign Name. We can also notice the bulb icon next to the field.

A screenshot of a computer

AI-generated content may be incorrect.

Clicking on it, we can see our message –

A screenshot of a web page

AI-generated content may be incorrect.

Similarly, on changing the Lead Source to Web, we are changing the label to Landing Page, and clicking on the icon, we can see a different message.

A screenshot of a web page

AI-generated content may be incorrect.

Sample Code –

function updateSubjectField(executionContext) {
	
    var formContext = executionContext.getFormContext();
    var leadSourceAttr = formContext.getAttribute("leadsourcecode");
    var subjectControl = formContext.getControl("subject");
   
    subjectControl.clearNotification("subjectTooltip");

    var leadSource = leadSourceAttr ? leadSourceAttr.getValue() : null;

    if (leadSource === 1) { 
        // 1 = Advertisement
        subjectControl.setLabel("Campaign Name");
        subjectControl.addNotification({
            messages: ["Enter the name of the ad campaign"],
            notificationLevel: "RECOMMENDATION",
            uniqueId: "subjectTooltip"
        });
    }
    else if (leadSource === 2) { 
        // 2 = Referral
        subjectControl.setLabel("Referrer Notes");
        subjectControl.addNotification({
            messages: ["Mention details about the referrer"],
            notificationLevel: "RECOMMENDATION",
            uniqueId: "subjectTooltip"
        });
    }
    else if (leadSource === 8) { 
        // 3 = Web
        subjectControl.setLabel("Landing Page");
        subjectControl.addNotification({
            messages: ["Provide the landing page URL"],
            notificationLevel: "RECOMMENDATION",
            uniqueId: "subjectTooltip"
        });
    }
    else {
        // Default
        subjectControl.setLabel("Subject");
    }
}

While addNotification isn’t a perfect replacement for a native tooltip, it’s a practical workaround when we need dynamic, context-aware user guidance.

Hope it helps..

Advertisements

Resolved – Environment Operation Error, while trying to copy environment (Dataverse / Power Platform)


Recently we created a new environment, and when we tried copying our production environment to it, it gave the below error.

“Environment Operation Error -Sorry, something went wrong while requesting the details of an ongoing operation”

A screenshot of a message

AI-generated content may be incorrect.

On trying to open the newly created environment, we got the below error.

“Environment Not Found -The environment was not found. This can happen if you recently performed an operation or switched accounts”

A screenshot of a computer error message

AI-generated content may be incorrect.

Shortly after that, we noticed the environment disappeared from the list of environments in the Power Platform Admin Center. To investigate what might have gone wrong, we raised a support ticket. However, after about an hour, the Admin Center began displaying the newly created environment we were copying to, and upon opening it, we saw the message – “The environment was successfully copied.”

A screenshot of a computer

AI-generated content may be incorrect.

We got the below explanation from Microsoft Support which clarified the behaviour – “If a copy operation begins but does not complete, particularly when using the “Copy over everything” option, the target environment may enter a missing or soft-deleted state. This is a known behavior in Power Platform, where environments can temporarily disappear from the environment list during long-running or interrupted operations.”

Hope it helps..

Advertisements

Clearing Dirty Fields in Forms to Avoid Unnecessary Save Prompts (Dynamics 365 / Dataverse)


In Dynamics 365 forms, we often run into situations where a record looks unsaved even though the user hasn’t made any manual changes. This usually happens when fields are updated in the background by scripts. When that happens, those attributes are flagged as dirty and the form behaves as if the user made edits. The result is that whenever users try to navigate away, they are interrupted by the familiar “You have unsaved changes” popup.

Also Check – https://nishantrana.me/2025/09/09/finding-dirty-unsaved-fields-on-the-form-using-javascript-browser-console-dynamics-365-dataverse/

In our case, we were getting this issue for fields which were already hidden from the form. Also here as the record was on a particular stage, where we were setting all the fields in the form read-only, and also cancelling the save event. Because of which user was also not able to save the form.

A computer screen shot of a computer program

AI-generated content may be incorrect.

The way we fixed this issue was to scan all the attributes on the form in onload, detect which ones are dirty and reset their submit behaviours. By setting their submit mode to “never“, these fields were not included in the save operation, and the form was now showing the saved state, thus no unsaved changes prompts.

clearAllDirtyFields: function (executionContext) {
    var formContext = executionContext.getFormContext();

    // Delay to allow system updates (rollups/calculated fields) to complete
    setTimeout(function () {
        formContext.data.entity.attributes.forEach(function (attr) {
            if (attr.getIsDirty()) {
                attr.setSubmitMode("never");
                console.log("Dirty flag cleared for: " + attr.getName());
            }
        });
        console.log("All dirty fields cleared from the form.");
    }, 3000); // adjust delay as needed
}

This approach should still be used with some caution. The best practice is to first understand why certain fields are showing as dirty and, if possible, fix the underlying cause. The script should only be used in specific situations where we are confident that the dirty fields are not needed for saving the record. It’s also important to add the right checks or conditions so that it doesn’t run everywhere unnecessarily.

For example, in our case we only applied it when the form was in a particular status where it was expected to be read-only for the user. The fields were already hidden, so letting them stay dirty served no purpose.

Hope it helps..

Advertisements

Easily Identify Control Names When a Field Appears Multiple Times in Forms (Dynamics 365/ Dataverse)


Sometimes when we are writing JavaScript in Dynamics 365, we need the exact schema name of a field’s control so that we can hide, show, or manipulate it properly. While the attribute’s schema name is straightforward, controls may have numbered names like gendercode1, gendercode2, etc., depending on how many times the field is placed on the form.

To quickly figure this out, we can run a small helper script directly in the browser console. This script highlights all instances of the field on the form, expands tabs/sections if they are collapsed, and shows the schema names against each control.

Here’s the script for the field gendercode: – specify the schema name and run it in console.

(function () {
    // configurable schema name
    var schemaName = "gendercode"; // change this as needed

    var formContext = Xrm.Page; 
    var attr = formContext.getAttribute(schemaName);
    if (!attr) { alert(schemaName + " not found"); return; }

    // clear old highlights/badges
    document.querySelectorAll('.schema-badge-' + schemaName).forEach(function(b){ b.remove(); });
    document.querySelectorAll('.schema-highlight-' + schemaName).forEach(function(e){
        e.style.outline = '';
        e.style.backgroundColor = '';
        e.classList.remove('schema-highlight-' + schemaName);
    });

    var names = [];
    var tabsExpanded = {};

    // expand tabs/sections containing the control
    attr.controls.forEach(function (ctrl) {
        var name = ctrl.getName();
        names.push(name);

        try {
            var section = ctrl.getParent && ctrl.getParent();
            var tab = section && section.getParent && section.getParent();
            if (tab && typeof tab.setDisplayState === 'function') {
                var tabName = tab.getName ? tab.getName() : null;
                if (!tabsExpanded[tabName]) {
                    try { tab.setDisplayState('expanded'); } catch (e) {}
                    tabsExpanded[tabName] = true;
                }
            }
            if (section && typeof section.setVisible === 'function') {
                try { section.setVisible(true); } catch (e) {}
            }
        } catch (e) {}
    });

    // highlight after expansion
    setTimeout(function () {
        attr.controls.forEach(function (ctrl, index) {
            var name = ctrl.getName();
            var el = findElementForControl(name);

            if (el) {
                el.classList.add('schema-highlight-' + schemaName);
                el.style.outline = "2px solid orange";
                el.style.backgroundColor = "#fff8e1";

                var badge = document.createElement("div");
                badge.className = "schema-badge-" + schemaName;
                badge.textContent = schemaName + " " + (index + 1);
                badge.style.cssText = "font-size:11px;color:white;background:orange;padding:1px 6px;margin-top:4px;border-radius:3px;display:inline-block";
                (el.parentElement || el).appendChild(badge);
            } else {
                console.warn("Could not find DOM element for control:", name);
            }
        });

        alert("Controls for " + schemaName + ":\n" + names.map(function(n,i){ return (i+1)+". "+n; }).join("\n"));
    }, 500);

    // helper to find DOM element for a control
    function findElementForControl(name) {
        var selectors = [
            '[data-id="' + name + '"]',
            '[id="' + name + '"]',
            '[id*="' + name + '"]',
            '[name="' + name + '"]',
            '[name*="' + name + '"]',
            '[aria-label*="' + name + '"]',
            '[data-id*="' + name + '"]'
        ];
        for (var i = 0; i < selectors.length; i++) {
            var node = document.querySelector(selectors[i]);
            if (node) return node;
        }
        var lab = document.querySelector('label[for="' + name + '"], label[for*="' + name + '"]');
        if (lab) return lab.closest('div.field-wrapper, .control, .ms-crm-Form-Field-Container') || lab.parentElement;
        return null;
    }

    // clear function
    window.clearHighlights = function () {
        document.querySelectorAll('.schema-badge-' + schemaName).forEach(function(b){ b.remove(); });
        document.querySelectorAll('.schema-highlight-' + schemaName).forEach(function(e){
            e.style.outline = '';
            e.style.backgroundColor = '';
            e.classList.remove('schema-highlight-' + schemaName);
        });
        try {
            var a = Xrm.Page.getAttribute(schemaName);
            if (a && a.controls) a.controls.forEach(function(c){ try{ c.clearNotification && c.clearNotification(); }catch(e){} });
        } catch (e) {}
        console.log(schemaName + ' highlights cleared');
    };
})();
A screenshot of a computer

AI-generated content may be incorrect.

When we run this in the console, it: Highlights all instances of the field with an orange outline and light background. Adds a small badge like gendercode 1, gendercode 2 next to each control. Alerts and logs the schema names so we can directly use them in our scripts.

This makes it very easy for us to identify which control name we should be using in our JavaScript.

Hope it helps..

Advertisements

Finding Dirty / Unsaved Fields on the Form Using JavaScript / Browser Console (Dynamics 365 / Dataverse)


Sometimes while debugging forms in Dynamics 365, we need to know which fields have been modified but not yet saved. These are called dirty fields, and they can be quickly identified by running a small JavaScript snippet directly from the browser console.

We can open the form, press F12 to bring up the developer tools, go to the Console tab, and paste the following code

(function () {
    var dirtyFields = [];
    var attributes = Xrm.Page.data.entity.attributes.get();

    attributes.forEach(function (attribute) {
        if (attribute.getIsDirty()) {
            dirtyFields.push(attribute.getName());
        }
    });

    if (dirtyFields.length) {
        alert("Dirty fields: " + dirtyFields.join(", "));
    } else {
        alert("No dirty fields found.");
    }
})();

This script loops through all the attributes on the form and checks if they are dirty using getIsDirty(). If it finds any, it shows their names in an alert, otherwise it shows a message saying no dirty fields are found.

For example, if we modify First Name and Email on the Contact form without saving, it will pop up an alert showing:

A screenshot of a computer

AI-generated content may be incorrect.

Here we are using Xrm.Page even though it is deprecated, because it is still the quickest way to test such snippets directly from the console for debugging purposes. In actual form scripts, we should always use formContext.

Hope it helps..

Advertisements